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 和方法调用。