主要问题是一旦你引用了一个项目,你不能移动该项目 https://stackoverflow.com/q/32300132/155423。让我们看一个简化的内存示例:
let a = Struct1; // the memory for Struct1 is on the stack at 0x1000
let b = &a; // the value of b is 0x1000
let c = a; // This moves a to c, and it now sits on the stack at 0x2000
哦不,如果我们尝试使用参考b
(仍然指向0x1000
),那么我们将访问未定义的内存!这正是 Rust 帮助预防的一类错误 - Rust 万岁!
如何解决取决于您的实际情况。在你的例子中,我建议moving the facade
进入线程,then创建RoutingNode
关于线程堆栈中的引用:
let facade = MyFacade;
let t = thread::spawn(move || {
let f = facade;
let r = RoutingNode::new(&f);
});
这是答案的一部分,人们通常会说“但是演示代码不是我真正的代码所做的”,所以我期待额外的复杂性!
不幸的是,我无法使用这个解决方案,因为我需要在将路由对象发送到另一个线程之前在主线程中使用路由对象
我在这里看到几个选项。最直接的是有包装对象取得所有权包装对象的,而不仅仅是一个引用:
use std::thread;
trait Facade: Sync {
fn add(&self) -> u32;
}
struct RoutingNode<F> {
facade: F,
}
impl<F> RoutingNode<F>
where
F: Facade,
{
fn new(facade: F) -> RoutingNode<F> {
RoutingNode { facade }
}
}
fn main() {
struct MyFacade;
impl Facade for MyFacade {
fn add(&self) -> u32 {
999u32
}
}
let facade = MyFacade;
let routing = RoutingNode::new(facade);
let t = thread::spawn(move || {
let r = routing;
});
t.join().expect("Unable to join");
}
另一种选择是使用作用域线程 https://stackoverflow.com/q/32750829/155423。这允许您拥有一个可以从闭包外部引用的线程,但是必须加入在借用的变量超出范围之前。作用域线程的两个潜在提供者:
- 横梁 https://crates.io/crates/crossbeam
- 作用域线程池 https://crates.io/crates/scoped_threadpool
使用横梁:
extern crate crossbeam;
let facade = MyFacade;
let routing = RoutingNode::new(&facade);
crossbeam::scope(|scope| {
scope.spawn(|| {
let r = routing;
})
});
如果第一个选项对您的情况具有语义意义,我更喜欢第一个选项。我也喜欢第二个选项,因为线程的生命周期通常不需要是整个程序。