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であるかどうかをコンパイル時に認識しません。