Why is Swift nil-coalescing returning optional?

First I'll try matching [String?] To get [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] = "" } 

That makes sense to me. Am I nil-coalesce a String? , and I get a String . But something strange happens to [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 have zero-coalescing optionals, but this time I choose optional. Why?

Swift programming language says that a ?? b a ?? b is short for a != nil ? a! : b a != nil ? a! : b a != nil ? a! : b , but when I try to do this, I get an array of non- -optionals:

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

I do not understand how it works ?? ? What's going on here?

+7
type-inference swift
source share
2 answers

It occurred to me that Apple considers this a bug in Swift 2.

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

Replacing an AnyObject ad with Any works: a ?? b a ?? b then behaves the same with a != nil ? a! : b a != nil ? a! : b a != nil ? a! : b , as the documentation says.

0
source share

Detailed behavior is poorly documented, so they have changed in future Swifts.

But you should know that the 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 chose the latter for your code.

You can test using simplified codes, for example:

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

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

 let y: AnyObject = x ?? "" 

String literals, such as "" , can be considered as many types. All of them are valid in Swift.

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

So, with some vague reason that Swift chose AnyObject? . And, if type inference can be ambiguous, you should use explicit type annotation, as suggested in the appzYourLife comment.

+2
source share

All Articles