为什么 Swift nil-coalescing 返回一个 Optional?

Why is Swift nil-coalescing returning an Optional?

首先,我尝试映射 [String?],得到 [String]:

$ xcrun swift
Welcome to Apple Swift version 2.2 (swiftlang-703.0.18.8 clang-703.0.30). Type :help for assistance.
  1> import Foundation
  2> let j: [String?] = ["a", nil]
j: [String?] = 2 values {
  [0] = "a"
  [1] = nil
}
  3> j.map {[=11=] ?? ""}
$R0: [String] = 2 values {
  [0] = "a"
  [1] = ""
}

这对我来说非常有意义。我没有合并 String?,得到 String。但是对于 [AnyObject?],会发生一些奇怪的事情:

  4> let k: [AnyObject?] = ["a", nil]
k: [AnyObject?] = 2 values {
  [0] = "a"
  [1] = nil
}
  5> k.map {[=12=] ?? ""}
$R1: [AnyObject?] = 2 values {
  [0] = "a"
  [1] = (instance_type = 0x00007fff7bc2c140 @"")
}

我没有合并可选项,但这次我得到了一个可选项。为什么?

Swift Programming Languagea ?? b 对于 a != nil ? a! : b 是 shorthand,但是当我尝试这样做时,我得到了一个非可选数组:

  6> k.map {[=13=] != nil ? [=13=]! : ""}
$R2: [AnyObject] = 2 values {
  [0] = "a"
  [1] = ""
}

我是不是误解了 ?? 的工作原理?这是怎么回事?

详细的行为没有很好的记录,因此,将来会改变 Swifts。

但是你应该知道合并运算符有两个重载:

@warn_unused_result
public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T

@warn_unused_result
public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T?) rethrows -> T?

在您的情况下,Swift 为您的代码选择了后者。

您可以使用以下简化代码进行测试:

let x: AnyObject? = "a"
x ?? ""

推断类型(在 Swift 2.2.1 中)变为 AnyObject?。 但是这段代码也是有效的。

let y: AnyObject = x ?? ""

"" 这样的字符串文字可以被视为多种类型。所有这些都在 Swift.

中有效
"" as String
"" as String?
"" as NSString
"" as NSString?
"" as AnyObject
"" as AnyObject?

因此,由于某些未指明的原因,Swift 选择了 AnyObject?。 而且,如果类型推断可能不明确,您应该使用显式类型注释,如 appzYourLife 的评论中所建议的那样。

我注意到 Apple 认为这是 Swift 2.

中的错误

在 Swift3 中,上面的第一个例子仍然有效,而第二个和第三个例子是无效的语法(有或没有 Foundation 桥接)。

AnyObject 声明替换为 Any 有效:a ?? b 的行为与 a != nil ? a! : b 相同,如文档所述。