1

当构建数组的变量nil最初是 a 时,就会出现问题。

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)
                     ^~~~

我该如何正确应对?
或者它可能等待 stdlibsum方法或其他任何更好的实现?

UPD:inject给出相同的:

p z.inject{ |i, j| i + j }

undefined method '+' for Nil (compile-time type is (Nil | Int32))
4

2 回答 2

4

您可以使用Iterator#compact_map来选择非零值。在这种情况下,编译器将能够推断出 a 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可能会导致不同的结果。第一个是编译时类型,后一个是运行时类型。

于 2015-09-08T03:52:08.680 回答
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
于 2015-09-08T15:05:44.117 回答