我无法向自己解释的简单代码:
puts a if a = 1
Run Code Online (Sandbox Code Playgroud)
这导致了
warning: found = in conditional, should be ==
NameError: undefined local variable or method 'a' for main:Object
Run Code Online (Sandbox Code Playgroud)
虽然现在经过检查a
我们可以看到它已被定义:
a #=> 1
Run Code Online (Sandbox Code Playgroud)
尽管抛出了异常,为什么a
还要分配1
?
来自文档:
混淆来自表达式的无序执行.首先分配局部变量,然后尝试调用不存在的方法[
a
].
这部分仍然令人困惑 - 为什么解释器没有检测到已定义的局部变量a
,仍然试图调用"不存在"的方法?如果它也不检查局部变量,找到定义的局部变量a
并打印1
?
让我们来看看Ruby的修饰符的抽象语法树if
:
$ ruby --dump=parsetree -e 'puts a if a = 1'
# @ NODE_SCOPE (line: 1, code_range: (1,0)-(1,15))
# +- nd_tbl: :a
# +- nd_args:
# | (null node)
# +- nd_body:
# @ NODE_PRELUDE (line: 1, code_range: (1,0)-(1,15))
# +- nd_head:
# | (null node)
# +- nd_body:
# | @ NODE_IF (line: 1, code_range: (1,0)-(1,15))
# | +- nd_cond:
# | | @ NODE_DASGN_CURR (line: 1, code_range: (1,10)-(1,15))
# | | +- nd_vid: :a
# | | +- nd_value:
# | | @ NODE_LIT (line: 1, code_range: (1,14)-(1,15))
# | | +- nd_lit: 1
# | +- nd_body:
# | | @ NODE_FCALL (line: 1, code_range: (1,0)-(1,6))
# | | +- nd_mid: :puts
# | | +- nd_args:
# | | @ NODE_ARRAY (line: 1, code_range: (1,5)-(1,6))
# | | +- nd_alen: 1
# | | +- nd_head:
# | | | @ NODE_VCALL (line: 1, code_range: (1,5)-(1,6))
# | | | +- nd_mid: :a
# | | +- nd_next:
# | | (null node)
# | +- nd_else:
# | (null node)
# +- nd_compile_option:
# +- coverage_enabled: false
Run Code Online (Sandbox Code Playgroud)
对于标准if
:
$ ruby --dump=parsetree -e 'if a = 1 then puts a end'
# @ NODE_SCOPE (line: 1, code_range: (1,0)-(1,24))
# +- nd_tbl: :a
# +- nd_args:
# | (null node)
# +- nd_body:
# @ NODE_PRELUDE (line: 1, code_range: (1,0)-(1,24))
# +- nd_head:
# | (null node)
# +- nd_body:
# | @ NODE_IF (line: 1, code_range: (1,0)-(1,24))
# | +- nd_cond:
# | | @ NODE_DASGN_CURR (line: 1, code_range: (1,3)-(1,8))
# | | +- nd_vid: :a
# | | +- nd_value:
# | | @ NODE_LIT (line: 1, code_range: (1,7)-(1,8))
# | | +- nd_lit: 1
# | +- nd_body:
# | | @ NODE_FCALL (line: 1, code_range: (1,14)-(1,20))
# | | +- nd_mid: :puts
# | | +- nd_args:
# | | @ NODE_ARRAY (line: 1, code_range: (1,19)-(1,20))
# | | +- nd_alen: 1
# | | +- nd_head:
# | | | @ NODE_DVAR (line: 1, code_range: (1,19)-(1,20))
# | | | +- nd_vid: :a
# | | +- nd_next:
# | | (null node)
# | +- nd_else:
# | (null node)
# +- nd_compile_option:
# +- coverage_enabled: false
Run Code Online (Sandbox Code Playgroud)
唯一的区别是方法参数puts
:
# | | | @ NODE_VCALL (line: 1, code_range: (1,5)-(1,6))
# | | | +- nd_mid: :a
Run Code Online (Sandbox Code Playgroud)
VS:
# | | | @ NODE_DVAR (line: 1, code_range: (1,19)-(1,20))
# | | | +- nd_vid: :a
Run Code Online (Sandbox Code Playgroud)
使用修饰符if
,解析器将其a
视为方法调用并创建一个NODE_VCALL
.这指示解释器来进行方法调用(虽然有是一个局部变量a
),产生了NameError
.(因为没有方法a
)
使用标准if
,解析器将其a
视为局部变量并创建一个NODE_DVAR
.这指示解释器查找按预期工作的局部变量.
如您所见,Ruby在解析器级别识别局部变量.这就是文档说的原因:(强调添加)
由于解析顺序,修饰符和标准版本不是彼此的精确转换.
归档时间: |
|
查看次数: |
116 次 |
最近记录: |