1

Setter 在类内工作;REPL 顶层失败

在一个相关的问题中,我试图理解为什么赋值方法返回了一个意外的值,并了解到这是一个令人惊讶但记录在案的 Ruby 边缘案例。然而,当我试图调试这个问题时,我更深入地了解了兔子洞,并遇到了一些我无法解释的额外惊喜。

类内的二传手

当我在一个类中有一个 setter 方法时,例如:

class Setter
  def foo=(bar)
    @foo = Integer(bar).succ
  end
end

然后我从 setter 方法的返回值中得到了记录的奇怪,但实例变量仍然设置正确。例如:

s = Setter.new
s.foo = 1
#=> 1

s.instance_variable_get :@foo
#=> 2

REPL 顶级对象中的设置器

但是,在 REPL(例如 Pry 或 IRB)中,实例变量从未实际设置,尽管我的理解是实例变量应该存储在顶层“主”对象中:

self.name
#=> NoMethodError: undefined method `name' for main:Object

# This is expected to set the @foo instance variable for main.
def foo= int
  @foo = int
end

foo = 1

@foo
#=> nil

instance_variable_get :@foo
#=> nil

TOPLEVEL_BINDING.eval('self').instance_variables
#=> []

然而,顶层对象确实存储了实例变量!例如:

@bar = 1 + 1; @bar
#=> 2

instance_variable_get :@bar
#=> 2

问题,重述

鉴于 REPL 存储实例变量,为什么类赋值方法有效而顶层赋值方法失败?我希望两者都以相同的方式运作。

4

1 回答 1

1

=如果您没有明确写出接收者,Ruby 的赋值运算符将创建一个局部变量。在你的情况下:

foo = 1

正在创建一个局部变量foo而不是调用方法foo=。你必须使用

self.foo = 1

实际调用您在上面定义的方法。现在将设置@foo

def foo= i # define foo= on self
  @foo = i
end
#=> :foo=

foo = 3
#=> 3

@foo
#=> nil

foo # here's the new local variable
#=> 3

instance_variables
#=> [:@prompt]

instance_variable_get :@foo 
#=> nil

self.foo = 4 # now calling the foo= method
#=> 4

foo # local foo is still 3
#=> 3

@foo # now the ivar is set
#=> 4

在您的课程示例中,您有一个显式接收器,带有s.foo = 1. Ruby 然后知道您正在调用foo=setter on s分配方法文档说:

使用方法分配时,您必须始终有一个接收器。如果你没有接收者,Ruby 假设你正在分配一个局部变量[.]

于 2016-11-04T17:51:41.823 回答