跳至內容

if var.nil?

如果 if 的條件是 var.nil?,則編譯器會知道 then 分支中 var 的型別為 Nil,而在 else 分支中則已知為非 Nil

a = some_condition ? nil : 3
if a.nil?
  # here a is Nil
else
  # here a is Int32
end

實例變數

透過 if var.nil? 進行的型別限制只會發生在區域變數上。在類似上述程式碼範例中,實例變數的型別仍然是可為空的,並且會拋出編譯錯誤,因為 greet 預期在 unless 分支中接收一個 String

class Person
  property name : String?

  def greet
    unless @name.nil?
      puts "Hello, #{@name.upcase}" # Error: undefined method 'upcase' for Nil (compile-time type is (String | Nil))
    else
      puts "Hello"
    end
  end
end

Person.new.greet

您可以先將值儲存在區域變數中來解決此問題。

def greet
  name = @name
  unless name.nil?
    puts "Hello, #{name.upcase}" # name will be String - no compile error
  else
    puts "Hello"
  end
end

這是 Crystal 中多執行緒的副產品。由於存在 Fibers,Crystal 在編譯時無法知道當到達 if 分支中的使用位置時,實例變數是否仍然是非 Nil 的。