“未定义的方法'零'代表Nil:Class”当#sum没有Nils的数组时

时间:2015-09-08 03:28:59

标签: compile-time weak-typing crystal-lang

当构建数组的变量最初为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))

2 个答案:

答案 0 :(得分:4)

您可以使用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可能会导致不同的结果。第一个是编译时类型,后一个是运行时类型。

答案 1 :(得分: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