当#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 的未定义方法‘零’”的主要内容,如果未能解决你的问题,请参考以下文章

15. 3Sum

数据结构_线性结构(稀疏数组)

16. 3Sum Closest

数据结构与算法学习之(稀疏数组)

数字为 sum s 的 k 位整数数组

Lua 正则表达式