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)
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、数组中的 map 和 flatMap 数组中的 map 对数组元素进行某种规则的转换,例如: 二、 flatM...
    kmplayer阅读 4,091评论 0 6
  • 对各种值为"空"的情况处理不当,几乎是所有Bug的来源。 在我们的例子里,尽管tmp的值是nil,但调用tmp的r...
    AKyS佐毅阅读 10,559评论 1 13
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,908评论 18 139
  • map 和 flatMap 是 Swift 中两个常用的函数,它们体现了 Swift 中很多的特性。对于简单的使用...
    SwiftCafe阅读 1,582评论 5 16
  • 震荡了一天, 看强不强,看弱不弱。3100的支撑效应仍旧明显。有没有国家队进场我并不知道,我只知道如果延续这种走...
    光生丨寒夜阅读 239评论 0 0