【Tips】map & flatMap

前言

在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
RxSwift.Just
RxSwift.Empty
RxSwift.Just

结果截然不同!所以下面笔者说下自己的理解:
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(_ transform: (Element) -> T) -> [T] {
        var result: [T] = []
        result.reserveCapacity(count)
        for x in self {
            result.append(transform(x))
        }
        return result
    }
    
    func myFlatten(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(_ 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)