Optional 中的 map 和 flatMap

最近在国外的网上看到一篇介绍 Optional 中 map 和 flatMap 的文章(需要翻墙),觉得受益良多,给大家分享一下。如果你不知道 Swift 中的 map 和 flatMap,可以看看唐巧的Swift 烧脑体操(四) - map 和 flatMap,这篇文章也有介绍 Optional 中的 map 和 flatMap。

我们先看一个例子

var value: Int? = 2
var newValue = value.map { $0 * 2 }
// newValue is now Optional(4)

value = nil
newValue = value.map { $0 * 2 }
// newValue is now nil

在 Optional 中,map 方法不会关心自己是否是.None,可以直接进行修改,而如果不用 map,那么可能要先保证自己不是.None才能进行修改,比如我们对上面的例子做一个修改

if value != nil {
  newValue = value! * 2
}

如果我们要对 value 进行运算,那么首先要保证 value 有值才能进行,相比于用 map 的方式,很明显要臃肿。
map 方法提供了一种无需对 Optional 进行解包就可以直接修改的方式,很便捷。
我们再来看看 flatMap

value = 10
newValue = value.flatMap{ $0 / 5 }
// newValue is now Optional(2)

咋一看,好像没啥区别,那么换一种写法

newValue = value.map({ (i) -> Int in
    i / 5
})

newValue = value.flatMap({ (i) -> Int? in
    if i < 5 {
        return nil
    }
    return i / 5
})

此时我们可以看到,map 和 flatMap 在闭包中的返回值是不同的,map 的返回值不能是 nil,但是 flatMap 可以。我们在具体使用时,要根据 Closure 中的返回值类型来选择不同的方法。

再来几个例子:

String 字面量值

// Without map:
func ageToString(age: Int?) -> String {
    return age == nil ? "Unknown age" : "She is \(age!) years old"
}

// With map:
func ageToString(age: Int?) -> String {
    return age.map { "She is \($0) years old" } ?? "Unknown age"
}

本地化 String

// Without map:
let label = UILabel()
func updateLabel(value: String?) {
  if let value = value {
    label.text = String.localizedStringWithFormat(
      NSLocalizedString("value %@", comment: ""), value)
  } else {
    label.text = nil
  }
}

// With map:
let label = UILabel()
func updateLabel(value: String?) {
  label.text = value.map { 
    String.localizedStringWithFormat(NSLocalizedString("value %@", comment: ""), $0) 
  }
}

根据某一条件在数组中找到对应元素

struct Item {
    let identifier: String
}
let items: [Item]

// Without map:
func find(identifier: String) -> Item? {
    if let index = items.indexOf({$0.identifier == identifier}) {
        return items[index]
    }
    return nil
}

// With map:
func find(identifier: String) -> Item? {
    return items.indexOf({$0.identifier == identifier}).map({items[$0]})
}

解析 Json 字典

struct Person {
    let firstName: String
    let lastName: String

    init?(json: [String: AnyObject]) {
        if let firstName = json["firstName"] as? String, let lastName = json["lastName"] as? String {
            self.firstName = firstName
            self.lastName = lastName
            return
        }
        return nil
    }
}

// Without map:
func createPerson(json: [String: AnyObject]) -> Person? {
    if let personJson = json["person"] as? [String: AnyObject] {
        return Person(json: personJson)
    }
    return nil
}

// With map:
func createPerson(json: [String: AnyObject]) -> Person? {
    return (json["person"] as? [String: AnyObject]).flatMap(Person.init)
}

你可能感兴趣的:(Optional 中的 map 和 flatMap)