假设 foo
, bar
和 baz
没有被定义,那么这行代码
foo bar baz
会引发以下错误:
NameError(未定义的局部变量或主对象的方法`baz')
在Python、PHP和JavaScript的REPL中, foo(bar(baz))
的第一个问题是 foo
未定义。为什么Ruby首先抱怨 baz
?
假设 foo
, bar
和 baz
没有被定义,那么这行代码
foo bar baz
会引发以下错误:
NameError(未定义的局部变量或主对象的方法`baz')
在Python、PHP和JavaScript的REPL中, foo(bar(baz))
的第一个问题是 foo
未定义。为什么Ruby首先抱怨 baz
?
Ruby允许第一个被调用的方法(baz
)动态定义另外两个方法。它在实际的方法调用发生之前不会尝试解析foo
或bar
作为方法调用,并且因为baz
首先引起了错误,所以永远不会到达那个方法调用。
如果baz
动态定义了方法foo
和bar
,那就没有问题:
def baz
define_method(:foo) { |x| "foo #{x}" }
define_method(:bar) { |x| "bar #{x}" }
"baz!"
end
foo bar baz # => "foo bar baz!"
参考这篇文章ruby-magic-code-interpretation
在控制台中检查它
2.3.1 :001 > puts RubyVM::InstructionSequence.compile("foo bar baz").disasm
== disasm: #<ISeq:<compiled>@<compiled>>================================
0000 trace 1 ( 1)
0002 putself
0003 putself
0004 putself
0005 opt_send_without_block <callinfo!mid:baz, argc:0, FCALL|VCALL|ARGS_SIMPLE>, <callcache>
0008 opt_send_without_block <callinfo!mid:bar, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0011 opt_send_without_block <callinfo!mid:foo, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0014 leave
=> nil
NameError (undefined local variable or method `baz' for main:Object)
baz
)动态定义其他两个方法。” 在我看来,这似乎不太正确。 Ruby不会自动定义方法,而是在解析方法本身之前先解析参数。否则,在引发错误后您将能够调用foo
。 - 3limin4t0rbaz
会先被评估,而不是它是否可以定义另外两个方法(如果foo
首先被评估,您也可以在foo
中定义bar
和baz
)。这个答案基本上只是证明了OP已经注意到的内容,而不是提供一个答案。 - Mladen Jablanović