美文网首页Swift
Swift - 使用Optional的flatMap来让nil向

Swift - 使用Optional的flatMap来让nil向

作者: Zafir_zzf | 来源:发表于2019-06-26 19:33 被阅读0次

    背景

    当我知道Optional也有flatMap方法的时候我的内心是很惊讶的. 之前CollectionflatMap就因为两个重载方法搞得我晕了一阵.而且因为不常用对所以对flatMap一直没有一个概念. 最近一些对可选值的使用场景让我调研并使用了一下, 结合唐巧的一篇博客, 算是对flatMap这个关键词有了统一的认识.

    使用场景

    假设我们要设计一个函数, 函数参数是一个image的data, 我们要把它先转换为UIImage, 然后将其转换为jpg格式,压缩0.3倍, 然后返回压缩后的UIImage. 常规的话我们可能会这么写.

    func getCompressImage(by data: Data?) -> UIImage? {
            guard let data = data,
              let image = UIImage(data: data),
              let jpegImageData = image.jpegData(compressionQuality: 0.3),
              let compressImage = UIImage(data: jpegImageData) else {
                return nil
            }
            return compressImage
        }
    

    这样其实已经算是比较清晰了(比起if let)

    如果使用flatMap会是这样的

    func getCompressImage(by data: Data?) -> UIImage? {
         return data.flatMap {
                        UIImage(data: $0)
                    }.flatMap{
                        $0.jpegData(compressionQuality: 0.3)
                    }.flatMap{
                        UIImage(data: $0)
                    }
        }
    

    flatMap函数的核心思想是对一个容器的元素进行再变形,变形为新的容器, 这里的容器就是指Optional, 所以我们可以看到它可以将异常情况nil进行下沉. 在一步步的操作中我们并没有进行解包操作, 只是将有值得情况进行处理, nil的情况向下传递下去. 代码其实更清晰简洁了.
    并且不是类似的情况都能用guard let解决, 如果其中一个操作比较复杂,要进行

    这样还不能足够表现flatMap的好处. 先看一段传统写法的代码

    func getValue(with stringValue: String) -> String {
            guard let number = Int(stringValue), number > 100 else {
                return "default"
            }   
            let str = String(number + 100)
            if str == "1000" {
                return str
            } else {
                return "default"
            }
        }
    

    为了举例子写了一段没有具体需求的函数, 目的是为了让它无法简化多少.
    我们看到在两种为nil的情况下我们写了两次return "default"
    但是使用flatMap

     func getValue(with stringValue: String) -> String {
            return Int(stringValue).flatMap {
                return $0 > 100 ? nil : String($0 + 100)
            }.flatMap {
                $0 == "1000" ? "1000" : nil
            } ?? "default"
    }
    

    我们将两种可能为nil的情况传递到函数调用的末尾, 统一来返回default, 并且变化的过程看起来更简单清晰了
    你可以试一下如何优化第一种代码.. 我是不知道它如何能做到一次处理返回default

    总结

    flatMap虽然传的是一个函数, 里面可以做额外的操作, 但是我们最好只做变形操作.不能引发副作用是函数式编程的原则..
    另外Optional的这个函数虽然看起来挺酷, 但是使用不当也会增加阅读的复杂度,一个guard let就能解决的话还用个函数那就有些炫技的嫌疑了.
    对于flatMap的nil下沉我觉得是与其它解包方式最大的区别. 大家也可以多试试.

    flatMapmap区别

    在函数式编程里所有的集合类型都有这两个方法,
    除了集合类型, RxSwift里的Observable,和标准库里的Optional也有这两个方法, 它们的共性是对某一类型的元素进行了封装.
    我们先将这个封装了之后的类型叫做容器, 被封装的值叫做元素
    在集合类型里的元素很好理解, Optional容器里的元素就是someValue, Observable容器的元素就是观察的值

    mapflatMap都是容器将元素进行变形得到一个新的容器, 不同的是
    map的变形是 元素 -> 元素
    flatMap的变形是元素->容器
    套用到前面的几种容器类型就发现确实如此.... 主要区别在于transform函数的类型.

    相关文章

      网友评论

        本文标题:Swift - 使用Optional的flatMap来让nil向

        本文链接:https://www.haomeiwen.com/subject/tkhhcctx.html