DEV Community

loading...

Rust Future then map difference

x1957
・3 min read

一直好奇and_then, map有什么区别,感觉都是输入一个fn,然后返回一个Future。

看看文档就发现了

and_then

fn and_then<F, B>(self, f: F) -> AndThen<Self, B, F> 
where F: FnOnce(Self::Item) -> B,
        B: IntoFuture<Error=Self::Error>,
        Self: Sized
[]
Execute another future after this one has resolved successfully.

This function can be used to chain two futures together and ensure that the final future isn't resolved until both have finished. The closure provided is yielded the successful result of this future and returns another value which can be converted into a future.

Note that because Result implements the IntoFuture trait this method can also be useful for chaining fallible and serial computations onto the end of one future.

If this future is dropped, panics, or completes with an error then the provided closure f is never called.

Note that this function consumes the receiving future and returns a wrapped version of it.

Examples
use futures::future::*;

let future_of_1 = ok::<u32, u32>(1);
let future_of_4 = future_of_1.and_then(|x| {
    Ok(x + 3)
});

let future_of_err_1 = err::<u32, u32>(1);
future_of_err_1.and_then(|_| -> FutureResult<u32, u32> {
    panic!("should not be called in case of an error");
});

map

fn map<F, U>(self, f: F) -> Map<Self, F> 
where F: FnOnce(Self::Item) -> U, Self: Sized
[]
Map this future's result to a different type, returning a new future of the resulting type.

This function is similar to the Option::map or Iterator::map where it will change the type of the underlying future. This is useful to chain along a computation once a future has been resolved.

The closure provided will only be called if this future is resolved successfully. If this future returns an error, panics, or is dropped, then the closure provided will never be invoked.

Note that this function consumes the receiving future and returns a wrapped version of it, similar to the existing map methods in the standard library.

Examples
use futures::future::*;

let future_of_1 = ok::<u32, u32>(1);
let future_of_4 = future_of_1.map(|x| x + 3);

可以看到and_then的f返回的future应该是个unresolved的,map返回的是个solved的。

看看代码

#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
pub struct AndThen<A, B, F> where A: Future, B: IntoFuture {
    state: Chain<A, B::Future, F>,
}

pub fn new<A, B, F>(future: A, f: F) -> AndThen<A, B, F>
    where A: Future,
          B: IntoFuture,
{
    AndThen {
        state: Chain::new(future, f),
    }
}

impl<A, B, F> Future for AndThen<A, B, F>
    where A: Future,
          B: IntoFuture<Error=A::Error>,
          F: FnOnce(A::Item) -> B,
{
    type Item = B::Item;
    type Error = B::Error;

    fn poll(&mut self) -> Poll<B::Item, B::Error> {
        self.state.poll(|result, f| {
            result.map(|e| {
                Err(f(e).into_future())
            })
        })
    }
}
#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
pub struct Map<A, F> where A: Future {
    future: A,
    f: Option<F>,
}

pub fn new<A, F>(future: A, f: F) -> Map<A, F>
    where A: Future,
{
    Map {
        future: future,
        f: Some(f),
    }
}

impl<U, A, F> Future for Map<A, F>
    where A: Future,
          F: FnOnce(A::Item) -> U,
{
    type Item = U;
    type Error = A::Error;

    fn poll(&mut self) -> Poll<U, A::Error> {
        let e = match self.future.poll() {
            Ok(Async::NotReady) => return Ok(Async::NotReady),
            Ok(Async::Ready(e)) => Ok(e),
            Err(e) => Err(e),
        };
        e.map(self.f.take().expect("cannot poll Map twice"))
         .map(Async::Ready)
    }
}

map的实现比较简单,当future ready之后把返回值用f处理后返回新的Async::Ready包装后的Result. 不过and_then稍微复杂了点,多了个chain,我们看看chain的代码

#[derive(Debug)]
pub enum Chain<A, B, C> where A: Future {
    First(A, C),
    Second(B),
    Done,
}

impl<A, B, C> Chain<A, B, C>
    where A: Future,
          B: Future,
{
    pub fn new(a: A, c: C) -> Chain<A, B, C> {
        Chain::First(a, c)
    }

    pub fn poll<F>(&mut self, f: F) -> Poll<B::Item, B::Error>
        where F: FnOnce(Result<A::Item, A::Error>, C)
                        -> Result<Result<B::Item, B>, B::Error>,
    {
        let a_result = match *self {
            Chain::First(ref mut a, _) => {
                match a.poll() {
                    Ok(Async::NotReady) => return Ok(Async::NotReady),
                    Ok(Async::Ready(t)) => Ok(t),
                    Err(e) => Err(e),
                }
            }
            Chain::Second(ref mut b) => return b.poll(),
            Chain::Done => panic!("cannot poll a chained future twice"),
        };
        let data = match mem::replace(self, Chain::Done) {
            Chain::First(_, c) => c,
            _ => panic!(),
        };
        match f(a_result, data)? {
            Ok(e) => Ok(Async::Ready(e)),
            Err(mut b) => {
                let ret = b.poll();
                *self = Chain::Second(b);
                ret
            }
        }
    }
}

可以看到当a.poll执行完之后,拿到之前的fn,然后执行f(a_result, data),f是之前and_then里面的的函数

|result, f| {
    result.map(|e| {
        Err(f(e).into_future())
})

所以chain里面的match这里一定是个Err啦,这里的b就是f(e)之后生成的Future,并且这里改变了Chain的状态,Chain::Second(b),如果这里b.poll()返回Ready那么就结束了,如果是NotReady,那么下次poll的时候再match *self,就是b了,就直接poll b。

Discussion (0)