具有特征的生命周期和所有权
Lifetimes and ownership with traits
我正在构建一个 Rocket 应用程序并希望它为我管理一些对象。为此,它们需要 Send
和 Sync
。这是一个最小的人为示例,显示了我遇到的错误 (Playground):
trait MyTrait {
fn foo(&self) {}
}
struct TraitThing {}
impl MyTrait for TraitThing {
fn foo(&self) {
println!("Foo!");
}
}
struct Thing {
tt: &'static (dyn MyTrait + Send + Sync),
}
impl Thing {
fn with_trait(tt: &'static (dyn MyTrait + Send + Sync)) -> Self {
Self { tt }
}
}
fn main() {
let tt = TraitThing {};
let thing = Thing::with_trait(&tt);
thing.tt.foo();
}
我可能不明白 'static
的生命周期。理想情况下,我希望 Thing
拥有 tt
,但据我了解,由于我的 TraitThing 不是 Sized
(并且可能永远不会),它不可能是特征对象,所以它必须通过引用传递。
那么,如何在保持 Send
和 Sync
特征的同时解决这个问题?
谢谢!
附加说明:我在 Rust 书中和其他地方阅读了很多关于生命周期和特征的内容,但我希望进一步阅读 material。
您需要使用Box
:
trait MyTrait {
fn foo(&self) {}
}
struct TraitThing {}
impl MyTrait for TraitThing {
fn foo(&self) {
println!("Foo!");
}
}
struct Thing {
tt: Box<dyn MyTrait + Send + Sync>,
}
impl Thing {
fn with_trait(tt: Box<dyn MyTrait + Send + Sync>) -> Self {
Self { tt }
}
}
fn main() {
let tt = TraitThing {};
let thing = Thing::with_trait(Box::new(tt));
thing.tt.foo();
}
您可以使用 Box 但它会分配给堆并使用动态调度,这对您的情况没有用。当您想要一个实现类似特征的不同类型的列表时,它很有用,例如:
struct Thing {
tt: Vec<Box<dyn MyTrait + Send + Sync>>,
}
但在您的情况下,您只有一个元素,因此您可以在此设置中使用 泛型:
trait MyTrait {
fn foo(&self) {}
}
struct TraitThing {}
impl MyTrait for TraitThing {
fn foo(&self) {
println!("Foo!");
}
}
struct Thing<T>
where
T: MyTrait + Send + Sync
{
tt: T,
}
impl<T> Thing<T>
where
T: MyTrait + Send + Sync
{
fn with_trait(tt: T) -> Self {
Self { tt }
}
}
fn main() {
let tt = TraitThing {};
let thing = Thing::with_trait(tt);
thing.tt.foo();
}
我正在构建一个 Rocket 应用程序并希望它为我管理一些对象。为此,它们需要 Send
和 Sync
。这是一个最小的人为示例,显示了我遇到的错误 (Playground):
trait MyTrait {
fn foo(&self) {}
}
struct TraitThing {}
impl MyTrait for TraitThing {
fn foo(&self) {
println!("Foo!");
}
}
struct Thing {
tt: &'static (dyn MyTrait + Send + Sync),
}
impl Thing {
fn with_trait(tt: &'static (dyn MyTrait + Send + Sync)) -> Self {
Self { tt }
}
}
fn main() {
let tt = TraitThing {};
let thing = Thing::with_trait(&tt);
thing.tt.foo();
}
我可能不明白 'static
的生命周期。理想情况下,我希望 Thing
拥有 tt
,但据我了解,由于我的 TraitThing 不是 Sized
(并且可能永远不会),它不可能是特征对象,所以它必须通过引用传递。
那么,如何在保持 Send
和 Sync
特征的同时解决这个问题?
谢谢!
附加说明:我在 Rust 书中和其他地方阅读了很多关于生命周期和特征的内容,但我希望进一步阅读 material。
您需要使用Box
:
trait MyTrait {
fn foo(&self) {}
}
struct TraitThing {}
impl MyTrait for TraitThing {
fn foo(&self) {
println!("Foo!");
}
}
struct Thing {
tt: Box<dyn MyTrait + Send + Sync>,
}
impl Thing {
fn with_trait(tt: Box<dyn MyTrait + Send + Sync>) -> Self {
Self { tt }
}
}
fn main() {
let tt = TraitThing {};
let thing = Thing::with_trait(Box::new(tt));
thing.tt.foo();
}
您可以使用 Box 但它会分配给堆并使用动态调度,这对您的情况没有用。当您想要一个实现类似特征的不同类型的列表时,它很有用,例如:
struct Thing {
tt: Vec<Box<dyn MyTrait + Send + Sync>>,
}
但在您的情况下,您只有一个元素,因此您可以在此设置中使用 泛型:
trait MyTrait {
fn foo(&self) {}
}
struct TraitThing {}
impl MyTrait for TraitThing {
fn foo(&self) {
println!("Foo!");
}
}
struct Thing<T>
where
T: MyTrait + Send + Sync
{
tt: T,
}
impl<T> Thing<T>
where
T: MyTrait + Send + Sync
{
fn with_trait(tt: T) -> Self {
Self { tt }
}
}
fn main() {
let tt = TraitThing {};
let thing = Thing::with_trait(tt);
thing.tt.foo();
}