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

时间:2021-10-12 21:18:11

First, I try mapping a [String?], to get a [String]:

首先,我尝试映射[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] = ""
}

This makes perfect sense to me. I nil-coalesce a String?, and I get a String. But with [AnyObject?], something strange occurs:

这对我来说非常有意义。我没有合并一个字符串?,我得到一个字符串。但是对于[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 @"")
}

I'm nil-coalescing optionals, but this time I get out an optional. Why?

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

The Swift Programming Language says a ?? b is shorthand for a != nil ? a! : b, but when I try that, I get out an array of non-optionals:

Swift编程语言说? b是!= nil的简写?一个! :b,但是当我尝试这个时,我会得出一系列非选项:

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

Am I misunderstanding how ?? is supposed to work? What is going on here?

我误解了怎么办?应该工作吗?这里发生了什么?

2 个解决方案

#1


2  

The detailed behaviour is not well-documented, so, would change in the future Swifts.

详细的行为没有详细记录,因此,未来的Swifts会有所改变。

But you should know coalescing operator has two overloads:

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

@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?

In your case, Swift has chosen the latter for your code.

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

You can test with a simplified codes like:

您可以使用简化的代码进行测试,例如:

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

The inferred type (in Swift 2.2.1) becomes AnyObject?. But this code is also valid.

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

let y: AnyObject = x ?? ""

String literals like "" can be treated as variety of types. All of these are valid in Swift.

像“”这样的字符串文字可以被视为各种类型。所有这些在Swift中都是有效的。

"" as String
"" as String?
"" as NSString
"" as NSString?
"" as AnyObject
"" as AnyObject?

So, with some unspecified reason Swift has chosen AnyObject?. And, in case type inference can be ambiguous, you should use explicit type annotation, as suggested in appzYourLife's comment.

因此,有一些未说明的原因,Swift选择了AnyObject?。并且,如果类型推断可能不明确,您应该使用显式类型注释,如appzYourLife的注释中所建议的那样。

#2


0  

It has come to my attention that Apple considered this a bug in Swift 2.

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

In Swift 3, the 1st example above still works, while the 2nd and 3rd examples are invalid syntax (with or without Foundation bridging).

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

Replacing the AnyObject declaration with Any works: a ?? b then behaves identically to a != nil ? a! : b, as the documentation says.

用Any替换AnyObject声明:a ?? b然后表现与!= nil相同?一个! :b,正如文件所说。

#1


2  

The detailed behaviour is not well-documented, so, would change in the future Swifts.

详细的行为没有详细记录,因此,未来的Swifts会有所改变。

But you should know coalescing operator has two overloads:

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

@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?

In your case, Swift has chosen the latter for your code.

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

You can test with a simplified codes like:

您可以使用简化的代码进行测试,例如:

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

The inferred type (in Swift 2.2.1) becomes AnyObject?. But this code is also valid.

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

let y: AnyObject = x ?? ""

String literals like "" can be treated as variety of types. All of these are valid in Swift.

像“”这样的字符串文字可以被视为各种类型。所有这些在Swift中都是有效的。

"" as String
"" as String?
"" as NSString
"" as NSString?
"" as AnyObject
"" as AnyObject?

So, with some unspecified reason Swift has chosen AnyObject?. And, in case type inference can be ambiguous, you should use explicit type annotation, as suggested in appzYourLife's comment.

因此,有一些未说明的原因,Swift选择了AnyObject?。并且,如果类型推断可能不明确,您应该使用显式类型注释,如appzYourLife的注释中所建议的那样。

#2


0  

It has come to my attention that Apple considered this a bug in Swift 2.

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

In Swift 3, the 1st example above still works, while the 2nd and 3rd examples are invalid syntax (with or without Foundation bridging).

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

Replacing the AnyObject declaration with Any works: a ?? b then behaves identically to a != nil ? a! : b, as the documentation says.

用Any替换AnyObject声明:a ?? b然后表现与!= nil相同?一个! :b,正如文件所说。