嵌套Crystal对象上的Null Type过滤

我得到了

undefined method 'start_time' for Nil (compile-time type is (Reservation | Nil))

代码

if game.reservation && other_game.reservation
       if(game.reservation.start_time == other_game.reservation.start_time)                    
            return false 
       end
 end

但是,如果我这样做

reservation : Reservation | Nil = game.reservation
other_reservation : Reservation | Nil = other_game.reservation
if reservation && other_reservation
    if(reservation.start_time == other_reservation.start_time)                    
        return false 
    end
end

为什么这些表达式不等同?通常,if是一个类型过滤器,它从类型中删除 Nil union,但不是在它是嵌套对象时 . 第二种方式有效,但感觉不必要地冗长 .

What's the right way to perform a type filter with an if on a nested object?

回答(1)

3 years ago

让我们稍微简化一下(它仍然是同样的错误):

if game.reservation
  game.reservation.starting_time
end

条件确保 game.reservation 的返回值不是 nil . 这个表达式只是在 game 上调用方法 reservation . 之后不会重用返回的值,并且无法知道对同一方法的第二次调用是否可能返回 nil .

您可以通过将返回值存储在局部变量中来轻松解决此问题 . 这样编译器可以确定它的值不是 nil . 这甚至更高效,因为它节省了(可能代价高昂的)对同一方法的额外调用 .

if reservation = game.reservation
  reservation.starting_time
end

语言参考中更详细地解释了确切的行为:https://crystal-lang.org/docs/syntax_and_semantics/if_var.html