Первоначально пренебрегая комбинированное использование оператора 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()
}
}
Я думаю, что есть ошибка во втором фрагменте кода, так как foo1 и foo2 объявлены в равной степени есть. Не должно быть «foo2 = (s2 ?? ...»? – nbloqs
@nbloqs да, спасибо, опечатка от моего имени! – dfri
Я рад помочь! – nbloqs