【问题标题】:Crystal no overload matches 'Array(Type)#[]' with type (Int32 | Nil)Crystal 无重载匹配 'Array(Type)#[]' 类型 (Int32 | Nil)
【发布时间】:2016-11-19 18:16:07
【问题描述】:

我在使用索引时发现了一些奇怪的行为。

#Defined in the class's initialize    
@my_list = [] of Type

index = @my_list.index { |i| i.value == 2 } # => 0

@my_list[0] # => 2
@my_list[index] # => error

我得到错误:

没有重载匹配 'Array(Type)#[]' 类型为 (Int32 | Nil)

不知道为什么 index 不起作用,因为 index = 0。

编辑:

更多信息。如果我这样做:

if index == nil
  #Do something
#error => undefined method '>=' for Nil (compile-time type is (Int32 | Nil))
elsif index >= 0
  #Do something else
end

我明白了。它可能为零,但由于我已经在检查它是否为零,所以这里不应该有问题。我认为之前的代码 sn-p 遇到了同样的问题。

【问题讨论】:

    标签: crystal-lang


    【解决方案1】:

    问题是 Array#index 是可空的;它可能找不到任何东西并返回 nil,因此它返回一个 Int32|Nil 联合。

    编译器最终会失败,因为 Array#[] 需要一个 Int32 参数,但我们向它传递了一个 Int32|Nil。您必须通过检查返回值是否为真来处理这种情况(以避免以后出现错误)。

    【讨论】:

      【解决方案2】:

      正如@julien-portalier 所说:

      问题是 Array#index 是可空的;它可能在数组中找不到任何东西并返回 Nil,因此它返回一个 (Int32 | Nil) 联合。

      您可以使用Object#not_nil! 获取 Nil 类型的乘车:

      @my_list = [2, 4, 6, 8]
      
      index = @my_list.index { |i| i == 6 }.not_nil! # => 2
      # compile type of 'index' is Int32
      
      @my_list[0] # => 2
      @my_list[index] # => 6
      

      它将确保Array#index返回的类型不是Nil,如果是,则会引发异常(参见Nil#not_nil!


      如果你需要在不使用异常的情况下处理索引错误,你可以简单地检查Array#index是否失败:

      @my_list = [2, 4, 6, 8]
      
      index = @my_list.index { |i| i == 6 } # => 2
      # compile-time type of 'index' is (Int32 | Nil)
      
      if index
          # In this scope, compile-time type of 'index' is Int32
          @my_list[0] # => 2
          @my_list[index] # => 6
      end
      

      【讨论】:

        【解决方案3】:

        我只是这样做:

        def get_index(val)
          i = 0
          while i < @my_list.size
            if @my_list[i].value == val
               return i
            end
        
            i += 1
          end
        
          return -1
        end
        

        这种方式只会返回 int 值,不返回 nil。它似乎工作正常。

        【讨论】:

          【解决方案4】:

          更好的方法是使用times 方法,它更简单、更清晰:

          def get_index(val)
            @my_list.size.times do |i|
              return i if @my_list[i] == val
            end
            -1
          end
          

          UPD

          或者更简单

          def get_index(val)
            @my_list.index { |value| value == val } || -1
          end
          

          【讨论】:

            猜你喜欢
            • 2018-12-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-04-23
            • 2014-05-28
            • 1970-01-01
            • 2023-03-29
            • 1970-01-01
            相关资源
            最近更新 更多