How to borrow as mutable in a for

Hello,

I'm trying to collect futures on vector of struct, but i don't know how to deal with mutable restrictions. There a minimal code reproduction:

Cargo.toml

[dependencies]
futures = "0.3.8"

[dependencies.async-std]
version = "1.8.0"
features = ["unstable"]

main.rs

use async_std::pin::Pin;
use async_std::task;
use futures::future::join_all;
use std::time::Duration;
use async_std::prelude::*;
use async_std::stream;

struct MyStruct {
    counter: i64,
}
impl MyStruct {
    pub async fn work(&mut self) {
        let mut interval = stream::interval(Duration::from_secs(1));
        while let Some(_) = interval.next().await {
            self.counter += 1;
            println!("Hello, world ! {}", self.counter)
        }
    }
}


async fn daemon() {
    let mut futures: Vec<Pin<Box<dyn futures::Future<Output = ()> + std::marker::Send>>> = vec![];
    let mut my_structs: Vec<MyStruct> = vec![
        MyStruct { counter: 0 }
    ];

    for my_struct in my_structs.iter_mut() {
        futures.push(Box::pin(my_struct.work()));
    }

    join_all(futures).await;
}

fn main() {
    task::block_on(daemon())
}

Execution of this code produce:

error[E0597]: `my_structs` does not live long enough
  --> src/main.rs:28:22
   |
28 |     for my_struct in my_structs.iter_mut() {
   |                      ^^^^^^^^^^ borrowed value does not live long enough
...
33 | }
   | -
   | |
   | `my_structs` dropped here while still borrowed
   | borrow might be used here, when `futures` is dropped and runs the `Drop` code for type `Vec`
   |
   = note: values in a scope are dropped in the opposite order they are defined

How to deal with my_structs here ? Thank's !

You can use FuturesOrdered or FuturesUnordered to solve this nicely

async fn daemon() {
    // use futures::stream::StreamExt;
    let mut my_structs: Vec<MyStruct> = vec![
        MyStruct { counter: 0 }
    ];
    let mut futures = futures::stream::FuturesUnordered::new();
    futures.extend(my_structs.iter_mut().map(|futures| my_struct.work()));

    // in case you want to do work, replace drop
    // with a closure that does the work, or the commented while loop
    futures.for_each(drop).await;
    // while let Some(item) = futures.next().await { /* body */ }
}

edit: The problem was that futures is declared before my_structs, so it get's dropped afterwards. Things on the stack get dropped in reverse order. But futures may have pointers into my_structs so it should be dropped before my_structs. This means it needs to be declared after

1 Like

Also, the trait object requires the argument to be static.

Hello @RustyYato
Thanks for tour time, i think it is unblocking me :slight_smile:

Hello @alice
What object are you talking about ?

A trait object is when you do dyn MyTrait. When you write dyn MyTrait, that disallows borrowed types by default. It would probably work if you added + '_ to the trait object.

1 Like

Okay thank's !