Can't return a value referencing data owned by the current function

Can anyone tell why got this error? bar.inner implemented Future, it returns some anonymous object implemented Future? thanks for you time.
click playground link

use std::future::Future;
use std::pin::Pin;
use futures::task::Context;
use futures::task::Poll;
use futures::TryFutureExt;

#[derive(Copy, Clone)]
struct Foo {
    val: u32,
}
impl Foo {
    pub fn new(val: u32) -> Self {
        Foo {val: val}
    }
    async fn do_something(&self) -> Result<u32, ()> {
       return Ok(self.val)
    }
}
impl Future for Foo {
    type Output = Result<Foo, ()>;
    fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
        Poll::Ready(Ok(Foo {val: self.val}))
    }
}
struct Bar {
    inner: Foo,
}
impl Bar {
    pub fn new(inner: Foo) -> Self {
        Bar {inner: inner}
    }
}
impl Future for Bar {
    type Output = Result<Self, ()>;
    fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
        Poll::Ready(Ok(Bar {inner: self.inner}))
    }
}
#[tokio::main]
async fn main() {
    let ret = Foo::new(0)
        .and_then(|foo| { Bar::new(foo) })
        .and_then(|bar| { bar.inner.do_something() } );
    ret.await;
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0515]: cannot return value referencing local data `bar.inner`
  --> src/main.rs:43:27
   |
43 |         .and_then(|bar| { bar.inner.do_something() } );
   |                           ---------^^^^^^^^^^^^^^^
   |                           |
   |                           returns a value referencing data owned by the current function
   |                           `bar.inner` is borrowed here

For more information about this error, try `rustc --explain E0515`.
error: could not compile `playground` due to previous error

This is because and_then passes ownership, so when you get bar, it's not stored in ret, it's not stored anywhere except the function argument. And function arguments are destroyed as soon as the function exits.

You need to ensure that bar is stored somewhere for longer, e.g. in a variable in the main function:

let maybe_bar = Foo::new(0)
        .and_then(|foo| { Bar::new(foo) });
let ret = maybe_bar.as_ref()
        .and_then(|bar_ref| bar_ref.inner.do_something());

Variables in Rust are semantically meaningful. foo().bar() is different from let x = foo(); x.bar().

with this I got new error.

error[E0599]: no method named as_ref found for struct futures::future::AndThen in the current scope
--> src/main.rs:43:21
|
43 | let ret = maybe_bar.as_ref()
| ^^^^^^ method not found in futures::future::AndThen<Foo, Bar, [closure@src/main.rs:42:19: 42:42]>

In that case use .await instead of chaining .and_then.

Alternatively, change the result to something that is self-contained, perhaps bar.inner.do_something().to_owned() (or clone() or something else depending on what type is it).

I managed fixed this with only one simple change. Just changed
async fn do_something(&self) to async fn do_something(self).
Click PlayGround Link
My understand is:

  1. Foo::new(1) create unamed object (I'll refer to foo) implement Future.
  2. So can call .and_then
    fn and_then<Fut, F>(self, f: F) -> AndThen<Self, Fut, F>
    where
        F: FnOnce(Self::Ok) -> Fut,
        Fut: TryFuture<Error = Self::Error>,
        Self: Sized,
    {
        assert_future::<Result<Fut::Ok, Fut::Error>, _>(AndThen::new(self, f))
    }

.and_then will consume foo, and return a new AndThen object(foo will moved to AndThen object)
3. same thing happens for second .and_then(|bar| bar.inner.do_something)
4. If do_something takes a reference in async function, as async function implement Future trait, internally Rust will create some state machine which need holds that reference to bar. But .and_then requires the closure is fnOnce, which consume the bar object(moved to new constructed AndThen object). that's why we got error. "returns a reference to data owned by the current function"

For other lost googlers: Another possible cause of the returns a value referencing data owned by the current function error is that you need to "clone" the return value in the closures, such that the value can be "moved" into the next one without dangling references.

Also note that if you're using Option<T> as your return types, you'll need to call .cloned(), NOT .clone() as I did at first erronously. The former makes a clone of the value inside the Option enum, versus the latter, which simply clones the "wrapper" but keeps holding the contents by-reference. (in cases where .cloned() is not available, you can call .map(...) instead, supplying the code that will return an owned version of the data, if possible)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.