大卫弗拉纳根的Ruby编程语言; Yukihiro Matsumoto,they state that the variable prefixes ($, @, @@) are one price we pay for being able to omit parentheses around method invocations。谁可以给我解释一下这个?
答案 0 :(得分:1)
这是我不成熟的意见。如果我错了,请纠正我。
假设实例变量没有@
前缀,那么我们如何声明实例变量?
class MyClass
def initialize
# Here foo is an instance variable
self.foo = 'bar'
end
# Here foo is an instance method
def foo
end
def bar
# Call method. No doubt.
self.foo()
# Call method? Access instance variable?
self.foo
end
end
在上面的例子中,使用假设语法
初始化实例变量foo
self.foo = 'bar'
因为我们必须有办法告诉ruby解释器foo
属于当前实例而不是局部变量。
然后在方法bar
中,如果在方法调用中没有强制使用括号,那么解释器如何判断self.foo
是方法调用还是实例变量访问?
也许我们可以在缺少括号时让实例变量影子实例方法,但这会导致语言本身的语法不一致。例如,从MyClass
定义之外:
obj = MyClass.new
# Call instance method
obj.foo
这是一个实例方法调用,因为所有实例变量都是从外部看不到的(至少不使用元编程)。但是方法self.foo
中的bar
(没有括号)是实例变量访问。这种语法不一致可能会导致错误。此外,它也难以实现解释器本身。
然后让实例方法影响实例变量呢?然后程序员必须确保实例变量名称不与实例方法名称冲突,否则实例变量将变得不可访问。如果一个类有一个很长的祖先链是非常困难的,因为不仅要检查当前类定义中的冲突,还要检查其祖先中的冲突,这会破坏封装。
无论哪种方式,价格远远高于为实例变量添加前缀。对于类和全局变量,情况类似。
答案 1 :(得分:0)
让我们看一个例子:
def foo
10
end
p foo
#=> 10
foo = 'hi'
p foo
#=> hi
p foo()
#=> 10
如果我们在同一范围内定义一个名称与方法名称相同的局部变量,那么我们将失去对方法名称的绑定,因为变量名称优先。为了消除歧义,人们将强制使用括号。
本书似乎详细阐述了这一现象,并且设计决策提供了灵活性,其中需要使用@
之类的符号来定义实例变量,以便各自的访问方法(var
& {可以在没有括号的情况下调用{1}}),并且可以获得一个人正在访问变量的印象,即使实际上是在调用方法。
...你会发现Ruby变量开头的标点字符 names:全局变量以$为前缀,实例变量为 以@为前缀,类变量以@@为前缀。这些 前缀可能需要一点时间习惯,但过了一段时间你可能会 来了解前缀告诉你的范围的事实 变量。需要前缀才能消除Ruby的歧义 非常灵活的语法。考虑变量前缀的一种方法是 它们是我们为能够省略括号而付出的一个代价 方法调用。