11

为什么在下面的代码片段中 foo 替换了它的定义?

def foo
  def foo
    1
  end
end

第一次foo是零

foo
=> nil

foo.foo
=> 1

现在,如果我foo再打电话:

foo
=> 1

如您所见foo,不再是 nil 了。谁可以给我解释一下这个?谢谢。

4

6 回答 6

7
def foo
  p "about to redef foo"
  def foo
    1
  end
end
foo
"about to redef foo"
=> nil
foo
=> 1

此外,当您调用 时foo.foo,似乎您正在尝试访问内部foo方法,但它不起作用。您的foo方法实际上是在 上定义的Object,因此您实际上是在调用1.foo.

于 2012-12-06T16:35:31.867 回答
1

如果你想要这个效果,试试

def foo
  foo = proc {
    1
  }
end

由于def方法不会创建新的self. 每个方法都绑定到selfmain在本例中是一个 Object.new ,它为 ruby​​ 解释器加载的每个文件实例化。在一个类里面,self就是类,你得到实例方法。

于 2012-12-06T16:49:12.993 回答
1

方法定义在读取时被解析,但在调用之前不会执行。当您执行第一个foo时,执行最外层foo,其定义Object#foo

def foo
  1
end

nil作为定义该方法的操作的返回值返回。从此,当你调用 时foo,新定义foo的会被执行,返回

1
于 2012-12-06T16:49:36.290 回答
0

当你第一次调用foo它返回方法foo,当你再次调用foo它返回 1。阅读闭包

于 2012-12-06T16:39:03.833 回答
0

ruby 中的嵌套方法定义令人困惑。

它们实际上是重新定义!

发生的情况是这两个定义都适用于最外层的上下文。那就是两个定义都定义了相同的(!)方法 foo。虽然外部定义在读取文件时被解释,而内部定义仅在第一次调用外部方法时被解释。然后它将替换初始定义。

鉴于此代码

def foo
  def foo
    1
  end
end

让我们来看看:

  1. 加载文件时foo,使用 body 定义了一个全局方法def foo; 1; end
  2. 当您调用foo()此全局方法时,将执行并使用 body重新定义全局方法 ,并返回,因为定义方法没有返回值。foo1nil

  3. 当您调用foo().foo()全局方法并返回时,再次1执行全局方法,再次返回1

令人困惑的是两件事,a)嵌套方法定义都适用于相同的外部范围,b)可以在任何对象上调用全局方法。

这是另一个示例来演示嵌套定义实际上是如何重新定义的。

class A
  def m(arg=nil)
    def m; 42; end if arg
    23
  end
end

这就是发生的事情

a = A.new
a.m # => 23
a.m # => 23
a.m(:magic) # => 23
a.m # => 42
a.m # => 42

如您所见,嵌套定义实际上是重新定义。

于 2012-12-07T09:35:22.583 回答
0

就我个人而言,我一直认为它def在类上定义了 inner 很奇怪。我认为在单例上定义它更明智。例如等效于def self.foo,因为它是在实例级别而不是类级别调用的。

要么,要么它只能从它定义的方法中调用——尽管这可能没有那么有用,因为我们有 lambdas。

有一件事是肯定的,你几乎不会在实践中看到这一点。

于 2012-12-09T17:39:44.283 回答