1

The issue happens when the variable, that the array was built from, was a nil initially.

y = (1..2).map do
  v = nil
  v = 1
  v
end
p y       # => [1, 1]
p y.class # => Array(Int32)
p y.sum   # => 2

When v stops being nil on a condition, that is potentially computational and not solvable while compiling:

z = (1..2).map do
  v = nil
  v = 1 if true
  v
end
p z       # [1, 1]
p z.class # => Array(Nil | Int32)

The array gets more complex type, that isn't compatible with current sum implementation, so p z.sum causes compile time error:

undefined method 'zero' for Nil:Class (compile-time type is (Nil | Int32):Class)
 def sum(initial = T.zero)
                     ^~~~

How am I supposed to fight this properly?
Or maybe it waits for some better implementation of stdlib sum method or anything else?

UPD: inject gives the same:

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

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

2 に答える 2

4

Iterator#compact_mapnil 以外の値を選択するために使用できます。その場合、コンパイラは 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 に答える