2016-08-05 2 views
7

Во-первых, я пытаюсь отображения [String?], чтобы получить [String]:Почему Swift nil-coalescing возвращает необязательный?

$ 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] = "" 
} 

Это имеет смысл для меня. Я ноль-coalesce 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 @"") 
} 

Я Nil-сливающихся УСТРОЙСТВА, но на этот раз я выберусь необязательная. Зачем?

Swift Programming Language говорит a ?? b является сокращением для a != nil ? a! : b, но когда я пытаюсь что я получаю из массива, не являющихся дополнительными опциями:

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

ли я непонимание, как ?? должен работать? Что здесь происходит?

+2

Интересный вопрос, по той же причине это, похоже, работает 'let res: [AnyObject] = k.map {$ 0 ?? ""} ' –

+2

Похож на странную проблему вывода типа с' AnyObject' и литералами - это также работает: 'let k1 = k.map {$ 0 ?? String()} ' – Hamish

ответ

0

Он пришел к моему вниманию, что Apple, считает это ошибкой в ​​Swift 2.

В Swift 3, первый пример выше все еще работает, в то время как 2-й и 3-й примеры являются недействительным синтаксисом (с или без мостиков Foundation).

Замена AnyObject декларации с Any работ: a ?? b ведет себя идентично a != nil ? a! : b, как сказано в документации.

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.

+0

Интересно! Таким образом, похоже, что nil coalescing определяется * в * Swift, т. Е. Это не просто специальный синтаксис. Но тернарный оператор - это особый синтаксис, верно? Означает ли это, что правила вывода типов для перегрузок операторов (возможно, непреднамеренно) отличаются от правил ввода для встроенных операторов? –

+0

Возможно, я могу сказать «да» для обоих вопросов. Вы не можете писать никаких троичных операторов в Swift, даже если вы пытаетесь перегрузить существующие '?:'. И о правилах вывода типов, факт таков, как вы видите. И я не имею в виду, что это то, что должно быть. Учитывая случаи использования оператора ниль-коалесценции, Swift должен использовать не факультативную первую стратегию, я думаю. – OOPer

 Смежные вопросы

  • Нет связанных вопросов^_^