2017-02-20 8 views
0

Недавно я просмотрел этот фрагмент кода.Путаница на вложенном коалесцирующем операторе

let s1: String?? = nil 
(s1 ?? "inner") ?? "outer" // Prints inner 





let st2: String?? = .some(nil) 
(st2 ?? "inner") ?? "outer" // prints outer 

Не знаю, почему (s2 ?? "inner") возвращение nil. Полностью запутался в этом. Может кто-нибудь, пожалуйста, помогите мне понять причину.

ответ

2

Первоначально пренебрегая комбинированное использование оператора nil коалесцирующим: при работе (по некоторым причинам) с вложенными дополнительными типами, это может быть полезно для явного типа из типов (а не с использованием общего ? синтаксического сахара для каждого по желанию " уровень "). Например .:

let s1: Optional<Optional<String>> = nil 
    /* ^^^^^^^^^................^- 'nil' with regard to "outer" optional */ 

let s2: Optional<Optional<String>> = .some(nil) 
    /* ^^^^^^^^^................^- the "outer" optional has value .some(...), i.e, 
            not 'nil' which would be .none. 
       ^^^^^^^^^^^^^^^^-the "inner" optional, on the other hand, has 
            value 'nil' (.none) */ 

Использование явно набран вложенной дополнительный (String??) и анализа двух различных назначений, как указано выше, мы можем продолжить вычисляя коалесценции оператора два комбинированных nil вызовов на каждом отдельном случае. Становится очевидно, что:

let foo1 = (s1 ?? "inner") ?? "outer" // equals "inner" 
     /* ^^- is 'nil', hence the call to 's1 ?? "inner" will coalesce 
       to "inner", which is a concrete 'String' (literal), which 
       means the second nil coalescing operator will not coelesce 
       to "outer" */ 

let foo2 = (s2 ?? "inner") ?? "outer" // equals "outer" 
     /* ^^- is .some(...), hence the call to 's1 ?? "inner" will coalesce 
       to _the concrete value wrapped in 's1'_; namely 'nil', due some, .some(nil). 
       hence, (s1 ?? "inner") results in 'nil', whereafter the 2nd nil 
       coalescing call, 'nil ?? "outer"', will naturally result in 'outer' */ 

Ключ к пониманию несколько сложнее s2 дело в том, что применение оператора nil коалесцирующий с LHS (левая сторона), что .some(...)всегда будет приводить к значению, завернутые в.some(...), даже если обернутое значение является nil (или, .none).

Optional<SomeType>.some(someThing) ?? anotherThing 
// -> someThing, even if this happens to be 'nil' 

Это также вполне очевидно, если мы решили взглянуть на the stdlib implementation of the nil coalescing operator:

public func ?? <T>(optional: T?, defaultValue: @autoclosure() throws -> T) 
    rethrows -> T { 
    switch optional { 
    case .some(let value): 
    // in your example (s2 and leftmost ?? call), 'T' is Optional<String>, 
    // and 'value' will have the value 'nil' here (which is a valid return for 'T') 
    return value 
    case .none: 
    return try defaultValue() 
    } 
} 
+0

Я думаю, что есть ошибка во втором фрагменте кода, так как foo1 и foo2 объявлены в равной степени есть. Не должно быть «foo2 = (s2 ?? ...»? – nbloqs

+0

@nbloqs да, спасибо, опечатка от моего имени! – dfri

+0

Я рад помочь! – nbloqs

2
let st2: String?? = .some(nil) 
(st2 ?? "inner") ?? "outer" // prints outer 

Не знаю, почему (s2 ?? "внутренний") возвращение всухую

Потому что это то, что вы там поставили:

let st2: String?? = .some(nil) 
          ^^^ 

Сравнить:

let st2: String?? = .some("howdy") 
(st2 ?? "inner") ?? "outer" // prints howdy 
Смежные вопросы