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?
による型制約は、ローカル変数でのみ発生します。上記のコード例と同様のインスタンス変数の型は、依然としてnilableであり、unless
ブランチでgreet
が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のマルチスレッドの副産物です。ファイバーが存在するため、Crystalは、if
ブランチでの使用に到達したときに、インスタンス変数が依然として非Nil
であるかどうかをコンパイル時に認識しません。