具有特征的生命周期和所有权

Lifetimes and ownership with traits

我正在构建一个 Rocket 应用程序并希望它为我管理一些对象。为此,它们需要 SendSync。这是一个最小的人为示例,显示了我遇到的错误 (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(并且可能永远不会),它不可能是特征对象,所以它必须通过引用传递。

那么,如何在保持 SendSync 特征的同时解决这个问题?

谢谢!

附加说明:我在 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();
}

Playground

您可以使用 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();
}