当#sum 没有 Nils 的数组时,“Nil:Class 的未定义方法‘零’”
Posted
技术标签:
【中文标题】当#sum 没有 Nils 的数组时,“Nil:Class 的未定义方法‘零’”【英文标题】:"undefined method 'zero' for Nil:Class" when #sum the Array without Nils 【发布时间】:2015-12-03 14:37:46 【问题描述】:当构建数组的变量最初是 nil
时,就会出现问题。
y = (1..2).map do
v = nil
v = 1
v
end
p y # => [1, 1]
p y.class # => Array(Int32)
p y.sum # => 2
当v
在某个条件下不再是nil
时,这可能是计算性的,并且在编译时无法解决:
z = (1..2).map do
v = nil
v = 1 if true
v
end
p z # [1, 1]
p z.class # => Array(Nil | Int32)
数组得到更复杂的类型,与当前的sum
实现不兼容,所以p z.sum
导致编译时错误:
undefined method 'zero' for Nil:Class (compile-time type is (Nil | Int32):Class)
def sum(initial = T.zero)
^~~~
我应该如何正确应对?
或者它可能等待 stdlib sum
方法或其他任何更好的实现?
UPD:inject
给出相同的结果:
p z.inject |i, j| i + j
undefined method '+' for Nil (compile-time type is (Nil | Int32))
【问题讨论】:
【参考方案1】:您可以使用Iterator#compact_map
选择非零值。在这种情况下,编译器将能够推断出Array(Int32)
。
http://play.crystal-lang.org/#/r/e85
z = (1..2).map do
v = nil
v = 1 if true
v
end
pp typeof(z) # => Array(Nil | Int32)
pp z # => z = [1, 1]
y = z.compact_map(&.itself)
pp typeof(y) # => Array(Int32)
pp y # => y = [1, 1]
另外,请注意typeof(Expr)
和Expr.class
可能会导致不同的结果。第一个是编译时类型,后一个是运行时类型。
【讨论】:
【参考方案2】:Brian 所说的另一种解决方案是将sum
与块一起使用:
http://play.crystal-lang.org/#/r/ein
z = (1..2).map do
v = nil
v = 1 if true
v
end
puts z.sum |x| x || 0 #=> 2
【讨论】:
以上是关于当#sum 没有 Nils 的数组时,“Nil:Class 的未定义方法‘零’”的主要内容,如果未能解决你的问题,请参考以下文章