以这段代码为例:
int div = 0;
int res = 3/div;
如果您将其复制/粘贴到irb中,请运行:
class Thing
attr_accessor :options, :list
def initialize
@list = []
@options = { published_at_end: 'NOW', published_at_start: 'NOW-2DAYS' }
end
def run
# If you replace this comment with a debugger, the value of list is nil
list += _some_method(options)
return list
end
private
def _some_method(options)
[options[:published_at_start], 1, 2, 3, 4, options[:published_at_end]]
end
end
t = Thing.new
它将输出此错误:
t.run
如果您移除NoMethodError: undefined method `+' for nil:NilClass
行(仅留下+=
行),则返回return
...所以从我所知道的,它只是存在将[]
设置为+=
的{{1}}。
我还发现有趣的是,在<{em> list
调用之前行中的nil
值是nil
(请参阅我在代码示例中的评论)。
或者,如果您使用+=
代替<<
,您将获得预期的结果:
flatten
如果您将其复制/粘贴到irb中,请运行:
class Thing
attr_accessor :options, :list
def initialize
@list = []
@options = { published_at_end: 'NOW', published_at_start: 'NOW-2DAYS' }
end
def run
list << _some_method(options)
list.flatten
end
private
def _some_method(options)
[options[:published_at_start], 1, 2, 3, 4, options[:published_at_end]]
end
end
t = Thing.new
它将输出t.run
。
为什么['NOW-2DAYS', 1, 2, 3, 4, 'NOW']
会将+=
的值重置为list
?
另外,如何在调用nil
之前将其值设置为nil
?
半相关/有用的旁注 - 由于performance reasons,我将使用铲+=
)与<<
,但我仍然感兴趣为什么该变量将重置为flatten
。
答案 0 :(得分:7)
list += [1, 2, 3]
相当于:
list = list + [1, 2, 3]
因为这是一个assignment,Ruby会创建一个新的局部变量 list
,遮蔽你的list
方法。来自文档:
使用方法分配时,您必须始终拥有接收器。如果您没有接收器,Ruby假定您正在分配一个本地变量
更具体地说,当解析器遇到list
时,会创建局部变量list =
。与未初始化的实例变量和全局变量一样,它的值为nil
。因此,尝试评估作业的右侧list + [1, 2, 3]
失败了,因为它等同于:
nil + [1, 2, 3]
# NoMethodError: undefined method `+' for nil:NilClass
因此,为了得到预期的结果,你必须提供一个明确的接收者:
self.list += [1, 2, 3]
或者直接分配给实例变量:
@list += [1, 2, 3]
或者使用修改接收器的方法:
list.concat [1, 2, 3]
答案 1 :(得分:1)
我相信list += _some_method(options)
正在内部编译为list = list + _some_method(options)
。尽管存在list
方法,但Ruby将list = :anything
解释为定义名为list
的新局部变量,从而在方法调用的范围内覆盖list
的解释。当Ruby错误地跳到“局部变量”结论时,必须用self.
告诉它。这就是切换到self.list += _some_method(options)
的原因。
class Thing
def foo; 'BAR'; end
def baz; foo = 'ODD'; foo; end
end
Thing.new.foo #=> "BAR"
Thing.new.baz #=> "ODD"
但我同意使用list <<
后跟flatten(1)
仍然更有效。