use std::rc::Rc;
use tokio::task::yield_now;
fn spawner() {
tokio::spawn(example());
}
async fn example() {
let non_send = Rc::new(1);
println!("{}", non_send);
yield_now().await;
}
报错信息
future cannot be sent between threads safely
within impl Future<Output = ()>
, the trait Send
is not implemented for Rc<i32>
, which is required by impl Future<Output = ()>: Send
rustcClick for full compiler diagnostic
lib.rs(15, 17): future is not Send
as this value is used across an await
spawn.rs(167, 21): required by a bound in tokio::spawn
想问下为什么non_send 在await之后已经未使用了,为什么还会捕获到future里,而不是有类似(NLL)类型效果判定其生命周期就到await之前那,不会捕获到futrue里
1
共 5 条评论, 1 页
评论区
写评论查了下NLL相关的RFC文章,这个
生命周期和作用域是相互关联的,作用域通常相当于某个块,更具体地说,是从
let
声明延伸到封闭作用域结束的块的后部。Rust 的生命周期比作用域灵活得多,非词法生命周期(NLL)主要就是让引用的生命周期更加灵活的。你说的这个问题,以前也有人提出过。从之前的经验上讲,要缩短值的作用域,一般就是手动调用
drop(x)
移出当前大的作用域,或者使用{}
限制作用域大小。也希望以后能支持你说的新特性吧,可以合理可靠地控制值的作用域大小,以减小边际作用影响
将 NoSendHasDrop 替换成 MutexGuard 就合理了
嗯 用{}将non_send 括起来就好了,感觉是有点不合理
--
👇
TinusgragLin: 我简化了一下,试了下这段代码:
会出现一致的编译错误,如果改成:
或:
或去掉 NoSendHasDrop 的 Drop impl 或 !Send impl
就可以通过了,我猜是
NoSendHasDrop
有 Drop 之后编译器就要在作用于结尾插个 drop,这样就延长了 unused 的生命,感觉编译器是不是在 borrow check 之前没进行足够的未使用代码删减?感觉可以到 github 提个 issue。
我简化了一下,试了下这段代码:
会出现一致的编译错误,如果改成:
或:
或去掉 NoSendHasDrop 的 Drop impl 或 !Send impl
就可以通过了,我猜是
NoSendHasDrop
有 Drop 之后编译器就要在作用于结尾插个 drop,这样就延长了 unused 的生命,感觉编译器是不是在 borrow check 之前没进行足够的未使用代码删减?感觉可以到 github 提个 issue。
因为编译器会把整个 async 函数的上下文打包成一个状态机,会捕获所有范围内局部的变量 就算不用,也算做 Future 的一部分,要求你实现 Send