My Playground 代码:
let nickName: String? = nil
let fullName: String = "John Appleseed"
let informalGreeting = "Hi (nickName ?? fullName)"
嗨约翰
let informalGreeting2 = "Hi (fullName ?? nickName)"
我嗨可选("约翰苹果种子")
以为我明白了第一种情况
let informalGreeting = "Hi (nickName ?? fullName)"
昵称为 nil,因此输出必须是"Hi \(fullName)" => "Hi John Appleseed">
在第二种情况下
let informalGreeting2 = "Hi (fullName ?? nickName)"
第一个值 fullName 不是 nil ,所以输出应该是 "Hi \(fullName)" => "嗨约翰苹果种子" 在我看来。
但是为什么输出是可选的包装输出,如下所示
嗨可选("约翰苹果种子")
有两个??
运算符:
public func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T
public func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T?) rethrows -> T?
如果我们通过忽略第二个参数来简化声明 一个可能抛出的自动关闭,我们得到
public func ??<T>(optional: T?, defaultValue: T) -> T // (1)
public func ??<T>(optional: T?, defaultValue: T?) -> T? // (2)
在nickName ?? fullName
中,第一个参数是可选的 第二个是非可选的,这意味着第一个变体是 使用,结果是非可选的:
nickName ?? fullName // (String? ?? String) -> String
如果nickName != nil
则结果是解开包装(!nickName
, 否则fullName
.
在fullName ?? nickName
中,第一个参数是非可选的 第二个是可选的。这与任何那些都不匹配 函数声明。
编译器所做的是将第一个参数"包装"到 可选,以使其编译(使用第二个变体)。 结果是可选的:
fullName ?? nickName // (String? ?? String?) -> String?
结果将始终是Optional(fullName)
.
在已编译的项目中,您还将收到警告
警告:nil 合并运算符 '??' 的左侧具有非可选类型"String",因此从不使用右侧
链接 nil 合并运算符时通常使用第二种变体:
let result = optA ?? optB ?? optC ?? nonOptD
(2) (2) (1)
问题是昵称是可选的,所以在第二种情况下,你告诉如果全名是 nil 打印昵称,但昵称可以是 nil,所以它会打印 嗨可选("约翰苹果种子"),
使用时?? 总是在它前面放一个可选变量,但在它后面放一个不是可选的字符串,它会正常工作。 希望这有帮助。