为什么Ruby不允许使用包含与本地变量同名的字段阅读器的表达式来设置局部变量?

Isa*_* To 0 ruby

请考虑以下代码.

class A
  attr_reader :n

  def initialize
    @n = 1
  end

  def set_local_n
    n = 10
  end

  def using_field_reader_locally
    n + 100
  end

  def using_field_reader_to_set_local_x
    x = n + 1000
  end

  def using_field_reader_to_set_local_n
    n = n + 1000  # This line raises a NoMethodError. Why?
  end
end
Run Code Online (Sandbox Code Playgroud)

为什么注释行会产生错误?为什么Ruby不允许设置局部变量,n在这种情况下,使用包含与本地变量同名的字段阅读器的表达式?为什么所有其他实例方法都会运行而没有任何问题但会using_field_reader_to_set_local_n产生错误.

请注意,我不打算定义n在本地using_field_reader_to_set_local_n与涉及本地定义的表达nset_local_n.我打算在n本地定义using_field_reader_to_set_local_n一个涉及现场读者的表达@n.定义set_local_n用于显示n可以在名为field的字段阅读器n存在的情况下在本地定义.

ndn*_*kov 7

如果你仔细一看,NoMethodError是不是那里是没有方法n,但方法+NilClass.

在这个声明中:

n = n + 1000
Run Code Online (Sandbox Code Playgroud)

Ruby必须决定什么n.当你为它分配东西时(n =)它不是一种方法.如果要调用该n=方法,则必须指定显式接收器(self.n =).

所以它必须是一个变量.在这种情况下局部变量.


现在要弄清楚:

n = n
Run Code Online (Sandbox Code Playgroud)

Ruby最终分配niln.这与内部必须为正在分配的变量名称放置占位符有关.


所以当你这样做时:

n = n + 1000
Run Code Online (Sandbox Code Playgroud)

会发生什么:

  1. n使用占位符值(nil)创建一个新的局部变量.
  2. 尝试分配给右边的任何东西.
  3. 计算右边的内容 - nil + 1000.
  4. nil没有+方法所以会引发错误.

要执行您想要执行的操作,您必须显式引用实例变量的值:

n = @n + 1000
Run Code Online (Sandbox Code Playgroud)

或者显式调用属性读取器:

n = self.n + 1000
Run Code Online (Sandbox Code Playgroud)

  • 像`foo`这样的简单引用可以是无接收器无参数消息发送(例如,等同于`self.foo()`)或局部变量解除引用.既然你可以很容易地告诉Ruby它是一个消息发送(通过添加一个像`self.foo`这样的接收器或添加像`foo()`这样的参数列表),如果有歧义,Ruby总是喜欢解释它作为局部变量的解引用.那么,什么是局部变量?当对一个裸标识符的赋值进行*解析时会创建一个局部变量*:`if false然后foo = 42 end; foo#=> nil`.`foo`被定义为局部变量,但未初始化 (4认同)