为什么 Ruby 顶层赋值方法无法在 REPL 中分配实例变量?
Why does a Ruby toplevel assignment method fail to assign instance variables in the REPL?
Setter 在 Class 内工作;在 REPL 顶级失败
在 , I was trying to understand why an assignment method was returning an unexpected value, and learned that this is a surprising but documented edge case 中 Ruby。但是,当我试图 调试 问题时,我更深入地了解了兔子洞,运行 发现了一些我无法解释的额外惊喜。
Setter里面一个Class
当我在 class 中有一个 setter 方法时,例如:
class Setter
def foo=(bar)
@foo = Integer(bar).succ
end
end
然后我从 setter 方法中得到了 return 值的记录奇怪,但实例变量仍然设置正确。例如:
s = Setter.new
s.foo = 1
#=> 1
s.instance_variable_get :@foo
#=> 2
Setter 在 REPL 顶级对象中
但是,在 REPL(例如 Pry 或 IRB)中,实例变量从未真正设置过,尽管我的理解是实例变量应该存储在顶层 "main" 对象中:
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存储了实例变量,为什么class赋值方法有效而顶层赋值方法失败了?我希望两者的功能相同。
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
在您的 class 示例中,您有一个带有 s.foo = 1
的显式接收器。 Ruby 然后知道你在 s
上调用 foo=
setter。 assignment methods documentation 表示:
When using method assignment you must always have a receiver. If you do not have a receiver, Ruby assumes you are assigning to a local variable[.]
Setter 在 Class 内工作;在 REPL 顶级失败
在
Setter里面一个Class
当我在 class 中有一个 setter 方法时,例如:
class Setter
def foo=(bar)
@foo = Integer(bar).succ
end
end
然后我从 setter 方法中得到了 return 值的记录奇怪,但实例变量仍然设置正确。例如:
s = Setter.new
s.foo = 1
#=> 1
s.instance_variable_get :@foo
#=> 2
Setter 在 REPL 顶级对象中
但是,在 REPL(例如 Pry 或 IRB)中,实例变量从未真正设置过,尽管我的理解是实例变量应该存储在顶层 "main" 对象中:
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存储了实例变量,为什么class赋值方法有效而顶层赋值方法失败了?我希望两者的功能相同。
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
在您的 class 示例中,您有一个带有 s.foo = 1
的显式接收器。 Ruby 然后知道你在 s
上调用 foo=
setter。 assignment methods documentation 表示:
When using method assignment you must always have a receiver. If you do not have a receiver, Ruby assumes you are assigning to a local variable[.]