美文网首页
【Tips】map & flatMap

【Tips】map & flatMap

作者: longjianjiang | 来源:发表于2017-07-24 07:07 被阅读160次

    前言

    在RxSwift中,map , flatMap两个操作符用的比较算是比较频繁的,开始的时候对flatMap理解并不是那么深刻,下面就一个例子来说下自己对于flatMap的认识:

     Observable.of(1, 2, nil ,4)
            .flatMap { $0 == nil ? Observable.empty() : Observable.just($0!) }
            .subscribe(onNext: {
                print($0)
            })
    

    开始

    其实说到flatMap,它相对于map的不同就是所谓的降维;但是如果用降维来解释如上的栗子,好像并不那么贴切?

    或许是笔者理解不够透彻,希望读者可以给出自己的解释

    接着

    因为栗子中的observable并不是所谓的inner observables;栗子中的输出结果是:

    1
    2
    4
    

    如果flatMap 换成map,输出结果如下:

    RxSwift.Just<Swift.Int>
    RxSwift.Just<Swift.Int>
    RxSwift.Empty<Swift.Int>
    RxSwift.Just<Swift.Int>
    

    结果截然不同!所以下面笔者说下自己的理解:
    mapflatMap,两个操作符都是将observable中的元素进行变换。map操作符变换后的元素类型就是闭包返回的类型,所以本文栗子中使用map后,订阅输出的就是RxSwift.%%类型;而flatMap闭包返回的类型都是Observable类型,但是变换后的元素是Observable类型中Element的类型,所以栗子中使用flatMap后输出的依然是 Int类型。
    栗子中flatMap闭包每次返回的Observable将其中的element发送到一个新的Observable,这个新的Observable会被订阅者所订阅,这个新的Observable就可以说明flatMap的降维,也是所谓的flat

    然后

    因为栗子中最初的Observable中有一个元素为空,所以ObservableElement类型应该是Optional,但是经过flatMap后输出的却不是,说明flatMap可以过滤Observable中为空的element
    之所以能过滤空的element,主要还是因为flatMap会新建一个Observable,因为栗子中闭包,当元素为空的时候返回的是一个空的Observable,所以新的Observable并不会接收到其中的element,之后订阅者所输出的也就不存在空的元素,所以类型自然也就不是Optional

    Swift中的flatMap,同样的也可以过滤空的元素

    ["ab", "cc", nil, "dd"].flatMap { $0 }
    ["ab", "cc", nil, "dd"].filter { $0 != nil} .map { $0! }
    

    此时数组是["ab", "cc", "dd"],而且不是Optional类型,只是使用flatMap更佳简洁高效;因为内部使用了if let,所以达到了过滤空元素的效果。

    Functor and Monad 更新于2017-12-04

    Functor and Monad是函数式编程的重要概念,笔者之前也不是太理解,只是听过名称而已,其实他们的定义和map,flatMap关系很大:

    flatMap其实是一种特殊的map,所谓的降维是因为flat的原因

    下面是笔者对于数组类型实现的map, flatten, flattenMap:

    extension Array {
        func myMap<T>(_ transform: (Element) -> T) -> [T] {
            var result: [T] = []
            result.reserveCapacity(count)
            for x in self {
                result.append(transform(x))
            }
            return result
        }
        
        func myFlatten<T>(elements: [[T?]]) -> [T] {
            var result: [T] = []
            
            for arr in elements {
                for item in arr {
                    if let num = item {
                        result.append(num)
                    }
                }
            }
    
            return result
        }
        
        func myFlattenMap<T>(_ transform: (Element) -> [T?]) -> [T] {
            return myFlatten(elements: myMap(transform))
        }
        
    }
    

    根据上面的代码,其实functor和monad的定义也就很容易理解了:

    Functor: map 函数接受一个闭包作为参数,作用与容器类型(数组,optional,result),通过传入的闭包改变容器类型内部的值,从而得到一个全新的容器; 所谓functor就是实现了map功能的类型;

    Monad: monad 是functor中的一种,相比functor不仅实现了map功能,而且实现了flattenMap的功能;

    相关文章

      网友评论

          本文标题:【Tips】map & flatMap

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