为什么foo不再为零 - 或者在函数内起作用

时间:2012-12-06 16:32:30

标签: ruby

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

def foo
  def foo
    1
  end
end

第一次foo为零

foo
=> nil

foo.foo
=> 1

现在,如果我再次致电foo

foo
=> 1

正如您所看到的,foo不再是零。谁可以给我解释一下这个?感谢。

6 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

如果您想要这种效果,请尝试

def foo
  foo = proc {
    1
  }
end

由于def方法不会创建新的self。每个方法都受到约束 到self,在这种情况下是main,是一个Object.new 为ruby解释器加载的每个文件实例化。里面一个 class,self是类,你得到实例方法。

答案 2 :(得分:1)

方法定义在读取时进行解析,但在调用之前不会执行。当您执行第一个foo时,会执行最外面的foo,将Object#foo定义为

def foo
  1
end

并返回nil作为定义方法的操作的返回值。从那时起,当您调用foo时,将执行新定义的foo,并返回

1

答案 3 :(得分:0)

当您第一次致电foo时,它会返回方法foo,当您再次致电foo时,它会返回1。 阅读closure

答案 4 :(得分:0)

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

它们实际上是重新定义!

两种定义都适用于最外层的情况。这两个定义都定义了相同的(!)方法foo。虽然在读取文件时会解释外部定义,但只在第一次调用外部方法时才会解释内部定义。然后它将取代初始定义。

鉴于此代码

def foo
  def foo
    1
  end
end

让我们来看看:

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

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

  4. 这里有两点困惑:a)嵌套方法定义既适用于同一外部作用域,又b)可以在任何对象上调用全局方法。

    这是另一个展示嵌套定义如何实际重新定义的例子。

    1

    这是发生的事情

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

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

答案 5 :(得分:0)

我个人总是认为它在类上定义内部def是非常奇怪的。我认为在单身人士上定义它更为明智。例如相当于def self.foo,因为它是在实例级别而不是类级别调用的。

或者它只能从它定义的方法中调用 - 虽然因为我们有lambdas而可能没那么有用。

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