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

时间:2016-08-05 21:26:14

标签: swift type-inference

首先,我尝试映射[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 {$0 ?? ""}
$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 {$0 ?? ""}
$R1: [AnyObject?] = 2 values {
  [0] = "a"
  [1] = (instance_type = 0x00007fff7bc2c140 @"")
}

我是零合并选项,但这次我选择了。为什么呢?

Swift Programming Languagea ?? ba != nil ? a! : b的简写,但是当我尝试这样做时,我会得到一系列非选项:

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

我是否误解了??应该如何运作?这是怎么回事?

2 个答案:

答案 0 :(得分:2)

详细的行为没有详细记录,因此,未来的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的注释中所建议的那样。

答案 1 :(得分:0)

我注意到Apple认为这是Swift 2中的一个错误。

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

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