Given following example:
// Cargo.toml
[package]
name = "unexpected-drop"
version = "0.1.0"
edition = "2021"
[dependencies]
futures = "0.3.28"
tokio = { version = "1.30.0", features = ["macros", "rt-multi-thread", "rt"] }
// main.rs
use {
futures::{
channel::mpsc::{unbounded, UnboundedReceiver},
stream, SinkExt, StreamExt,
},
std::iter::once,
};
struct Data {
pub receiver: UnboundedReceiver<usize>,
pub entity: usize,
}
impl Drop for Data {
fn drop(&mut self) {
println!("Dropping Data");
}
}
#[tokio::main]
async fn main() {
let (sender, receiver) = unbounded();
let entity = 0;
let data = Data { receiver, entity };
stream::iter(once(data))
.zip(stream::iter(once(sender)))
.for_each(|(/*mut*/ data, mut sender)| async move {
// let data_fix = data;
println!(
"Data entity: {}",
data /*_fix*/
.entity
);
assert!(sender.send(1).await.is_ok());
// let maybe_value = data.receiver.next().await;
// assert!(maybe_value.is_some());
// assert_eq!(maybe_value.unwrap(), 1);
})
.await;
}
This results in the following output:
Dropping Data
Data entity: 0
thread 'main' panicked at 'assertion failed: sender.send(1).await.is_ok()', src/main.rs:37:17
I tried this with the following rustc versions (output of cargo rustc -- --version
):
rustc 1.71.1 (eb26296b5 2023-08-03)
rustc 1.73.0-nightly (08d00b40a 2023-08-09)
I would have expected data not to be dropped before the end of the closure (or block? I am not 100% sure of the terminology here) and sender.send to be successful, even if I am not consuming the result via data.receiver. Even more confusingly, I seem to be able to use data.entity just fine even though data is dropped.
Uncommenting data_fix and using it instead of data fixes the issue. Another option is actually using data.receiver by uncommenting the lower 3 lines (and making data mut).
Glimpsing over the suggested forum threads and the rust references entries for block- and closure expressions didn’t yield any insight for me.
What am I missing here?