跳至内容

如果 var.nil?

如果 if 的条件是 var.nil? 那么编译器知道 then 分支中的 var 类型为 Nil,并且知道 else 分支中的 var 类型为非 Nil

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

实例变量

通过 if var.nil? 进行的类型限制只对局部变量有效。类似于上面代码示例中的实例变量类型仍然可以为空,并且由于 greetunless 分支中需要 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