跳至内容

if var

如果变量是 if 的条件,则在 then 分支中,变量将被视为不具有 Nil 类型。

a = some_condition ? nil : 3
# a is Int32 or Nil

if a
  # Since the only way to get here is if a is truthy,
  # a can't be nil. So here a is Int32.
  a.abs
end

这也适用于在 if 的条件中赋值的变量。

if a = some_expression
  # here a is not nil
end

此逻辑也适用于条件中包含 and (&&) 的情况。

if a && b
  # here both a and b are guaranteed not to be Nil
end

这里,&& 表达式的右侧也保证 a 不是 Nil

当然,在 then 分支中重新分配变量会导致该变量根据分配的表达式具有新的类型。

限制

上述逻辑**仅适用于局部变量**。它不适用于实例变量、类变量或在闭包中绑定的变量。这些类型的变量的值可能在条件检查后被另一个纤程影响,使其成为 nil。它也不适用于常量。

if @a
  # here `@a` can be nil
end

if @@a
  # here `@@a` can be nil
end

a = nil
closure = ->{ a = "foo" }

if a
  # here `a` can be nil
end

可以通过将值分配给新的局部变量来规避这种情况。

if a = @a
  # here `a` can't be nil
end

另一个选择是使用标准库中找到的 Object#try,它只在值不是 nil 时执行块。

@a.try do |a|
  # here `a` can't be nil
end

方法调用

该逻辑也不适用于 proc 和方法调用,包括 getter 和属性,因为 nilable(或更一般地说,联合类型)的 proc 和方法不能保证在两次连续调用时返回相同的更具体的类型。

if method # first call to a method that can return Int32 or Nil
  # here we know that the first call did not return Nil
  method # second call can still return Int32 or Nil
end

上面为实例变量描述的技术也适用于 proc 和方法调用。