Ruby 关于参数作用域的问题

runup · 2015年12月13日 · 最后由 darkbaby123 回复于 2015年12月13日 · 1981 次阅读

如下是元编程中的例子,在这个例子中,块中的 number 和第二出现的 number 不属于同一个作用域,但是按照元编程第三章内容,切割作用域的一般是 def,module,method,而这里均未出现,那如何判断这两个参数属于不同的作用域。

class Roulette
  def method_missing(name, *args)
    person = name.to_s.capitalize
    3.times do
      number = rand(10)+1
      puts "#{number}.."
    end
      "#{person} got a #{number}"
  end
end

3.times do #code end end 是另一个作用域门。method_missing 方法没有定义 number,这样第二个 number 是属于 类 Roulette 的实例方法。如果 没有定义的话 就会报“undefined local variable or method `number' for #Num:0x00000001564c48 (NameError)”。由于 没有找到 number 方法,则会调用 method_missing 方法,从而导致了死循环:“stack level too deep (SystemStackError)”。如果你在 3.times 之前定义了 number = xxx,number 变量可以进入 3.times 中进行运算。有点像外层的 变量可以跨过作用域的门到里面进行计算后,再出来。而外层没有定义的情况下,里面的变量是不能出来的吧

#1 楼 @pathbox end 是一个作用域的门的说法是第一次听说,刚刚在书中看到一句话,是说可以在块的内部定义额外的绑定,但是这些绑定在块结束时就消失了,我的理解是在块中定义的局部变量,在块外部是访问不到的,因此第二次出现的 number 会被当做是实例方法来进行调用。

这应该属于闭包的问题了吧?

嗯,可以这样理解。《The Well-Grounded Rubyist》这本书里面,是这样解释:Every definition block, whether for a class, a module, or a method, starts a new local scope—a new local-variable scratchpad—and gets its own variable a. This example also illustrates the fact that all the code in class- and module-definition blocks gets executed when it’s first encountered, whereas methods aren’t executed until an object is sent the appropriate message. block 里也有 local-variable。当一个局部变量第一次在出现,且是在 block 中出现,那么它的作用域就是 block,也就是在 block 中定义的额外绑定,但它的作用域就在该 block 内。如果在 block 外层就已经出现了,到 block 中不是第一次出现,则 block 中的该变量就是外层的局部变量。不知道可不可以这样理解

block 里面的是 variable,block 外面的是变成了 call method, class Roulette def method_missing(name, *args) person = name.to_s.capitalize number = nil 3.times do number = rand(10)+1 puts "#{number}.." end "#{person} got a #{number}" end end

3.times do .. end 的 block 也是作用域。其他的 block 比如 each 同理。

另外,虽然没实际跑过,但你这段代码最后的 "#{person} got a #{number}" 应该是获取不到 number 的,但也不会报错,因为你正好实现的是 method_missing …… 这样会循环调用直到栈溢出。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号