2017-02-13 5 views
1

Swift документация flatMap гласит:flatMap не отфильтровывать ноль, когда ElementOfResult выводится быть опционально

Возвращает массив, содержащий результаты, не Ниле вызова данного преобразования с каждым элементом этой последовательности.

В следующих примерах при возвращении тип ElementOfResult оставляется компилятору вывести flatMap работы как документировано, но в строке 5, когда ElementOfResult указано, таким образом, Inferred к Optional<String> типа, кажется, что flatMap перестает отфильтровывать nil «s.

Почему это так?

~ swift 
Welcome to Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1). Type :help for assistance. 
    1> let words = ["1989", nil, "Fearless", nil, "Red"] 
words: [String?] = 5 values { 
    [0] = "1989" 
    [1] = nil 
    [2] = "Fearless" 
    [3] = nil 
    [4] = "Red" 
} 
    2> words.flatMap { $0 } 
$R0: [String] = 3 values { 
    [0] = "1989" 
    [1] = "Fearless" 
    [2] = "Red" 
} 
    3> let resultTypeInferred = words.flatMap { $0 } 
resultTypeInferred: [String] = 3 values { 
    [0] = "1989" 
    [1] = "Fearless" 
    [2] = "Red" 
} 
    4> let resultTypeSpecified: [String?] = words.flatMap { $0 } 
resultTypeSpecified: [String?] = 5 values { 
    [0] = "1989" 
    [1] = nil 
    [2] = "Fearless" 
    [3] = nil 
    [4] = "Red" 
} 
+0

Помните, что 'flatMap (_ :)' возвращает '[ElementOfResult]', и возвращение замкнутости типа '' ElementOfResult?. Поэтому, если вы аннотируете возвращение как '[String?]', Вы говорите, что замыкание возвращает 'String ??'. Таким образом, необязательные элементы продвигаются к двойным обернутым опциям, и поэтому они являются '.some', поэтому они являются« non-'nil' ». Попробуйте аннотировать возврат 'flatMap (_ :)' как '[String]' вместо этого, как я показал в [мой ответ на ваш предыдущий вопрос] (http://stackoverflow.com/a/42213785/2976878). – Hamish

+0

Также см. Другие Q & A: [Swift flatMap на массиве с элементами необязательно имеет другое поведение] (http://stackoverflow.com/q/37505787/2976878) (возможно, обман?) – Hamish

ответ

2

Вот определение flatMap()

public func flatMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]

При установке типа resultTypeSpecified в [String?], компилятору, что ElementOfResult является Optional<String>.

Ваше закрытие трансформации имеет тип (String?) -> Optional<Optional<String>>.

flatMap заберет 1 "слой" опций, но не 2 слоя.

Надеюсь, этот пример будет делает вещи яснее:

let input: [String??] = [ 
    Optional.some(Optional.some("1989")), 
    Optional.some(Optional.none), 
    Optional.some(Optional.some("Fearless")), 
    Optional.some(Optional.none), 
    Optional.some(Optional.some("Red")) 
] 

let output = input.flatMap({ $0 }) 
Смежные вопросы