Ruby on rails Ruby变量定义
我在ruby中偶然发现了一个关于变量定义的奇怪行为(并在途中丢失了一盒甜甜圈): 在编译语言中,这甚至不会编译Ruby on rails Ruby变量定义,ruby-on-rails,ruby,abstract-syntax-tree,interpreted-language,Ruby On Rails,Ruby,Abstract Syntax Tree,Interpreted Language,我在ruby中偶然发现了一个关于变量定义的奇怪行为(并在途中丢失了一盒甜甜圈): 在编译语言中,这甚至不会编译 这是否意味着ruby保留了对该变量的引用,即使它没有通过该代码段 如果是,变量定义的ifs/else考虑的深度有多深 我真不敢相信这是ruby中的预期行为。而且它不是特定于irb的,在ruby/rails代码块中运行它会得到相同的结果。我可能在这方面错了,但是ruby为变量定义了作用域。 您拥有全局范围,即$ 然后您就有了运行脚本的本地范围,这就是您在问题中演示的范围。您可以在方法
- 这是否意味着ruby保留了对该变量的引用,即使它没有通过该代码段
- 如果是,变量定义的ifs/else考虑的深度有多深
我真不敢相信这是ruby中的预期行为。而且它不是特定于irb的,在ruby/rails代码块中运行它会得到相同的结果。我可能在这方面错了,但是ruby为变量定义了作用域。 您拥有全局范围,即$ 然后您就有了运行脚本的本地范围,这就是您在问题中演示的范围。您可以在方法内定义变量,但在运行脚本的本地范围内它仍然可用 资料来源: 这里说明了局部变量没有初始值nil,但是一旦定义,不管定义了什么,都会取它们的值
2.1.5 :001 > p 1
1
=> 1
2.1.5 :002 > p a
NameError: undefined local variable or method `a' for main:Object
from (irb):2
from /Users/deh0002a/.rvm/rubies/ruby-2.1.5/bin/irb:11:in `<main>'
2.1.5 :003 > if false
2.1.5 :004?> a = 2
2.1.5 :005?> else
2.1.5 :006 > a = 3
2.1.5 :007?> end
=> 3
2.1.5 :008 > p a
3
=> 3
2.1.5 :009 > p$a
nil
=> nil
2.1.5 :010 > p @a
nil
=> nil
2.1.5 :011 >
2.1.5:001>p1
1.
=> 1
2.1.5:002>PA
NameError:未定义的局部变量或main:Object的方法“a”
来自(irb):2
from/Users/deh0002a/.rvm/rubies/ruby-2.1.5/bin/irb:11:in`'
2.1.5:003>如果为假
2.1.5:004?>a=2
2.1.5:005?>其他
2.1.5:006>a=3
2.1.5:007?>结束
=> 3
2.1.5:008>PA
3.
=> 3
2.1.5:009>p$a
无
=>零
2.1.5:010>p@a
无
=>零
2.1.5 :011 >
区别在于全局变量和实例变量。即使没有定义它们,它们也会自动接受nil的值。在Ruby中,引用局部变量和发送给隐式接收器的消息(没有参数列表)之间存在歧义。这意味着
foo
可以表示“取消引用局部变量”或“不带参数将消息foo
发送到self
”,即,它可以等效于
binding.local_variable_get(:foo)
或
这种歧义在解析时得到解决。当解析器遇到对foo
的赋值时,从那时起,它将把foo
视为局部变量,而不管赋值是否实际执行。(这毕竟是解析器无法静态确定的。只需考虑如果rand>0.5,那么foo=42 end
)
在编译语言中,这甚至不会编译
没有编译语言这样的东西。编译和解释是编译器或解释器(duh!)的特性,而不是语言。语言既不编译也不解释。他们就是这样
每种语言都可以用编译器实现,每种语言都可以用解释器实现。大多数语言都有编译和解释实现(例如,C有GCC和Clang,它们是编译器,Cint和Cling,它们是解释器,Haskell有GHC,它们是编译器,Hugs,它们是解释器)
许多现代语言实现都在相同的实现中,或者在不同的阶段(例如,YARV和MRuby将Ruby源代码编译为内部字节码,然后解释该字节码),或者在混合模式引擎中(例如,HotSpot JVM同时解释和编译JVM字节码,这取决于哪个更有意义),或者两者兼而有之(例如,Rubinius在第一阶段将Ruby源代码编译成Rubinius字节码,然后两者都将该字节码编译成本机代码并进行解释,这取决于什么更有意义)
事实上,所有现有的Ruby实现都是编译的:YARV和MRuby编译成它们自己的内部字节码格式,Rubinius、MacRuby、MagLev和Topaz编译成它们自己的内部字节码格式,然后编译成本机代码,JRuby编译成JVM字节码(JVM可能会进一步编译,也可能不会进一步编译),IronRuby编译成CIL字节码(VES可能会进一步编译,也可能不会进一步编译)
Ruby这样做是因为语言规范这么说,而不是因为Ruby是“解释的”,因为事实上并非如此。Ruby唯一的纯解释实现是MRI和JRuby的早期版本,它们早就退役了。这是因为Ruby在解析时设置局部变量作用域。
a
在这个作用域中用作局部变量,所以Ruby将其视为局部变量(尽管它从未初始化)。@MarekLipka很有趣。我感觉到它可能与解析相关,这就是为什么我在这个问题上使用AST标记的原因。从编译参数的Good call中读取它,编程语言只是一个我可能永远不会忘记的短语。我不能因此而获得荣誉,我在采访中听到过,我相信是的。
foo
binding.local_variable_get(:foo)
self.foo()
# or
public_send(:foo)