为什么ruby中的变量前缀允许在方法调用中省略括号?

时间:2016-05-16 00:32:48

标签: ruby semantics

大卫弗拉纳根的Ruby编程语言; Yukihiro Matsumoto,they state that the variable prefixes ($, @, @@) are one price we pay for being able to omit parentheses around method invocations。谁可以给我解释一下这个?

2 个答案:

答案 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的歧义   非常灵活的语法。考虑变量前缀的一种方法是   它们是我们为能够省略括号而付出的一个代价   方法调用。