我有下面的Rust代码(rustc 1.75.0),它“强制”一个类型为Send:
struct ForceSend<T>(T);
unsafe impl<T> Send for ForceSend<T> {}
pub fn perform<T>(t: T) {
let wrapped = ForceSend(t);
takes_send(move || {
wrapped.0;
});
}
fn takes_send<F: Send>(_: F) {}
字符串
我希望这段代码能够编译,因为闭包通过move捕获了一个值wrapped
,这个值是Send。根据文档:
如果所有由非唯一不可变引用捕获的变量都是Sync,并且所有由唯一不可变或可变引用、复制或移动捕获的值都是Send,则闭包是Send。
然而,这无法编译,报告闭包是 not Send。
为什么这不编译?感谢任何帮助!
1条答案
按热度按时间xcitsw881#
wrapped.0
只从wrapped
中移动字段.0
,该字段的类型为T(非发送)。这通常对partial moves很有用,因为您可以移动捕获字段的子集,并将其余字段保持为未移动。在这种情况下,你必须确保你移动了 * 整个 *
wrapped
对象,例如通过创建一个绑定将整个Wrapped
移动到闭包中:字符串
playground(https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=617068a47c564a7e93f36d9d0c788394)的
另外,如果
T
确实是不受限制的,那么这段代码可能是不可靠的,如果takes_send
确实想跨线程发送东西,可能会导致UB。例如,如果从与获取线程不同的线程释放互斥/相关的某些操作系统实现,那么它会发生故障,跨线程发送MutexGuard
可能会产生这种情况。顺便说一句,这里有一个在捕获过程中部分移动行为的例子,在一个更有帮助的情况下:
型
playground(https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ee4c98c94dde25ad6cc42882ab5cc447)的