【问题标题】:"undefined method 'zero' for Nil:Class" when #sum the Array without Nils当#sum 没有 Nils 的数组时,“Nil:Class 的未定义方法‘零’”
【发布时间】: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))

【问题讨论】:

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


    【解决方案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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-06
        • 2021-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多