Как вы используете тождественное преобразование { $0 }
, компилятор будет считать, что ElementOfResult?
(результат преобразования) эквивалентно Element
(аргумент преобразования). В этом случае Element
- String?
, поэтому ElementOfResult?
== String?
. Здесь нет необходимости в дополнительном продвижении, поэтому ElementOfResult
можно определить как String
.
Поэтому flatMap(_:)
в этом случае возвращает [String]
.
Внутренне это преобразование из возврата закрытия ElementOfResult?
в ElementOfResult
выполняется просто путем условного разворачивания по желанию, и в случае успеха развернутое значение добавляется к результату. Вы можете увидеть exact implementation here.
В качестве дополнения, отметим, что as Martin points out, затворы только участвуют в умозаключения типа, когда они одной выписки закрытия (см this related bug report). Смысл этого был дан Jordan Rose in this mailing list discussion: определение типа
Свифта в настоящее время заявления-ориентированное, так что нет простого способа сделать [множественное заявление закрытия] умозаключение. Это, по крайней мере, частично связано со временем компиляции: система типов Swift допускает гораздо больше возможных преобразований, чем, скажем, Haskell или OCaml, поэтому решение типов для всей функции с несколькими операторами не является тривиальной проблемой, возможно, не приемлемой проблемой.
Это означает, что для закрытия с несколькими заявлениями, которые передаются такими методы, как map(_:)
или flatMap(_:)
(где тип результата является общим заполнителем), вам придется явно аннотирование типа возвращаемого закрытия, или метод возвращает себя.
Например, это не компилируется:
// error: Unable to infer complex closure return type; add explicit type to disambiguate.
let result = albums.flatMap {
print($0 as Any)
return $0
}
Но это сделать:
// explicitly annotate [ElementOfResult] to be [String] – thus ElementOfResult == String.
let result: [String] = albums.flatMap {
print($0 as Any)
return $0
}
// explicitly annotate ElementOfResult? to be String? – thus ElementOfResult == String.
let result = albums.flatMap { element -> String? in
print(element as Any)
return element
}
Возможно подчеркнуть, что тип возвращаемого значения выводится автоматически * закрытие одного выражения. * 'albums.flatMap {e in print (e); return e} 'не компилируется. –
@MartinR Yup, хорошая точка - спасибо за упоминание :) – Hamish
Хотя обременительно и удивительно, из отчета об ошибке сообщается, что на самом деле это не ошибка! – matt