最近在使用 inject 的时候遇到了一个问题。我的代码例子是:
[1,2,3,4,5,6].inject([]) do |sum, i|
if i > 1
sum << i
end
end
结果报错:
NoMethodError: undefined method `<<' for nil:NilClass
一开始很奇怪,在 inject([]) 的时候,我给 sum 赋值初始值为数组了,报错信息怎么会报 sum 是一个 nil:NilClass 呢?
打断点
def test_inject
[1,2,3,4,5,6].inject([]) do |sum, i|
if i > 1
binding.pry
sum << i
end
end
end
发现确实 sum 是 nil。想到了可能是 if i > 1 这个条件判断的影响。修改一下测试代码
def test_inject_0
[1,2,3,4,5,6].inject([]) do |sum, i|
if i > 0
sum << i
end
end
end
def test_inject_3
[4,5,6,1,2,3].inject([]) do |sum, i|
binding.pry
if i > 3
sum << i
end
end
end
test_inject_0 # [1, 2, 3, 4, 5, 6]
test_inject_3
sum
# []
# [4]
# [4,5]
# [4,5,6]
# NoMethodError: undefined method `<<' for nil:NilClass
根据 test_inject_3,当 i 的值不满足 if i > 3 的条件的时候,sum 的值就被置为 nil 了。
如果你需要在 inject 的 block 中进行对操作元素的条件过滤操作,你会将 sum 变为 nil。
所以建议不在 inject 的 block 中进行条件过滤操作,而是在 inject 方法之前过滤好。
同理 reduce 方法。
Ruby 版本:ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-linux]