【问题标题】:Why does a Ruby toplevel assignment method fail to assign instance variables in the REPL?为什么 Ruby 顶级分配方法无法在 REPL 中分配实例变量?
【发布时间】:2017-03-18 15:36:55
【问题描述】:

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

related question 中,我试图理解为什么赋值方法返回了一个意外的值,并了解到这是Ruby 中的surprising but documented edge case。然而,当我试图调试这个问题时,我更深入地了解了兔子洞并遇到了一些我无法解释的额外惊喜。

类内部的设置器

当我在一个类中有一个 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 存储实例变量,为什么类赋值方法有效而顶层赋值方法失败?我希望两者都以相同的方式发挥作用。

【问题讨论】:

  • 顺便说一句:我不同意评估分配值的方法分配是一个令人惊讶的边缘情况。它的工作方式与所有其他赋值完全相同:局部变量赋值、实例变量赋值、类变量赋值、全局变量赋值、常量赋值和索引赋值。 same 工作并不符合 IMO 的“边缘情况”,当然也不足为奇。 是一个边缘情况,并且令人惊讶的是,如果所有分配都工作相同除了一个!

标签: ruby setter instance-variables read-eval-print-loop toplevel


【解决方案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 知道您正在调用 s 上的 foo= 设置器。 assignment methods documentation 说:

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

【讨论】:

  • 它适用于类示例,因为您对接收者s.foo = 1很明确
  • 谢谢,我已经添加了sn-p。
猜你喜欢
  • 2011-09-25
  • 1970-01-01
  • 1970-01-01
  • 2018-02-15
  • 2013-03-21
  • 2015-11-05
  • 1970-01-01
  • 1970-01-01
  • 2017-12-27
相关资源
最近更新 更多