6

mapflatMapはどちらもImplicitlyUnwrappedOptionalで定義されていますが、ドキュメントによると定義が (明らかに) 異なります。

func map(f: @noescape (T) -> U) -> U!

自己 == nil の場合、nil を返します。それ以外の場合は、f(self!) を返します。

func flatMap(f: @noescape (T) -> U!) -> U!

f(自己) を返します! if self と f(self) は nil ではありません。

簡単な例でそれらを使用してみました:

let number: Int? = 1

let res1 = number.map { $0 + 1 }.map { $0 + 1 }
let res2 = number.flatMap { $0 + 1 }.flatMap { $0 + 1 }

res1 //3
res2 //3

しかし、それらは同じ結果numberをもたらしnil. ました どちらをいつ選択する必要がありますか?mapflatMapImplicitlyUnwrappedOptional

4

4 に答える 4

9

(注:の廃止など、Swift 3 以降の構文変更を反映するために回答が更新されましたImplicitlyUnwrappedOptional。)

Optional.map()そしてOptional.flatMap()、次のように宣言されます (ここでは無関係な throws/rethrows 修飾子を省略しました):

func map<U>(_ transform: (Wrapped) -> U) -> U?
func flatMap<U>(_ transform: (Wrapped) -> U?) -> U?

「マップ」を使用した最初の例の単純化されたバージョンを考えてみましょう。

let number: Int? = 1
let res1 = number.map { $0 + 1 }
print(res1) // Optional(2)

numberは型Int?を持ち、クロージャー型は と推測され(Int) -> Intます。UでありInt、戻り値の型は ですInt?numberは ではないnilので、アンラップさ1れてクロージャーに渡されます。クロージャは returnと return2map返しますOptional(2)。である場合、結果は になりnumberます。nilnil

次に、「flatMap」を使用した 2 番目の例の簡略版を検討します。

let number: Int? = 1
let res2 = number.flatMap { $0 + 1 }
print(res2) // Optional(2)

flatMapは type のクロージャを想定しています(Wrapped) -> U?{ $0 + 1 }、optional を返しません。コンパイルするために、コンパイラはこれを次のように変換します。

let res2 = number.flatMap { return Optional($0 + 1) }

これで、クロージャの typeが(Int) -> Int?になり、再びです。再びラップが解除され、クロージャに渡されます。クロージャーは、 からの戻り値でもある戻り値を返します。だった場合、またはクロージャーが返された場合、結果は になります。UIntnumberOptional(2)flatMapnumbernil nilnil

したがって、実際にはこれらの呼び出しに違いはありません。

let res1 = number.map { $0 + 1 }
let res2 = number.flatMap { $0 + 1 }

しかし、それflatMapは意図されたものではありません。より現実的な例は

func foo(_ s : String?) -> Int? {
    return s.flatMap { Int($0) }
}

print(foo("1")) // Optional(1)
print(foo("x")) // nil (because `Int($0)` returns nil)
print(foo(nil)) // nil (because the argument is nil)

一般に、型と変換mapのクロージャをとります(Wrapped) -> U

Optional<Wrapped>.none          --> Optional<U>.none
Optional<Wrapped>.some(wrapped) --> Optional<U>.some(transform(wrapped))

flatMap型のクロージャを取り、(Wrapped) -> U?変換します

Optional<Wrapped>.none          --> Optional<U>.none
Optional<Wrapped>.some(wrapped) --> transform(wrapped)

ここtransform(wrapped)もそうかもしれませんOptional<U>.none

(あなたの例のように)オプションを返さないflatMapクロージャで呼び出された場合、コンパイラはそれをオプションに自動的に変換し、もう違いはありません。map

于 2015-04-10T08:57:50.020 に答える
0

flatMapネストされたオプションを解決しますが、解決mapしません。

フラットマップ

var temp: Int? = 3
var flag: Bool = false
print(temp.flatMap { $0 < 5 ? 1 : nil } ?? .zero) 

// output: 1

地図

var temp: Int? = 3
var flag: Bool = false
print(temp.map { $0 < 5 ? 1 : nil } ?? .zero) 

// output: Optional(Optional(1))
于 2021-02-10T02:02:18.533 に答える