如何在Rust中创建一个需要生命周期的trait通用函数?

4

我正在尝试编写一个可以与数据库交互并表示可存储内容的trait。为此,这个trait继承了其他trait,其中包括serde :: Deserialize trait。

trait Storable<'de>: Serialize + Deserialize<'de> {
    fn global_id() -> &'static [u8];
    fn instance_id(&self) -> Vec<u8>;
}

struct Example {
    a: u8,
    b: u8
}

impl<'de> Storable<'de> for Example {
    fn global_id() -> &'static [u8] { b"p" }
    fn instance_id(&self) -> Vec<u8> { vec![self.a, self.b] }
}

接下来,我尝试使用通用函数编写此数据:

pub fn put<'de, S: Storable>(&mut self, obj: &'de S) -> Result<(), String> {
    ...
    let value = bincode::serialize(obj, bincode::Infinite);
    ...
    db.put(key, value).map_err(|e| e.to_string())
}

然而,我遇到了以下错误:
error[E0106]: missing lifetime specifier
--> src/database.rs:180:24
    |
180 |     pub fn put<'de, S: Storable>(&mut self, obj: &'de S) -> Result<(), String> {
    |                        ^^^^^^^^ expected lifetime parameter

在Playground上的最小示例。

我该如何解决这个问题,可能要避免它发生吗?

2个回答

4
你把'de的生命周期放错了位置——你需要将其用于指定Storable的参数,而不是引用obj的生命周期。

应该这样:

fn to_json<'de, S: Storable>(obj: &'de S) -> String {

使用

fn to_json<'de, S: Storable<'de>>(obj: &S) -> String {

Playground.

这里其实并不需要关心obj的生命周期,因为你没有返回任何与它相关的值。你只需要证明S实现了某个生命周期'de下的Storable<'de>接口。

如果你想完全消除'de,你可以使用DeserializeOwned,具体可参考其他答案


4
您已经定义了一个带有通用参数的 Storable,在这种情况下是一个生命周期。这意味着该通用参数必须在整个应用程序中传播:
fn put<'de, S: Storable<'de>>(obj: &'de S) -> Result<(), String> { /* ... */ }

您还可以决定使泛型更为具体。这可以通过具体类型或生命周期(例如,'static),或通过将其放在特征对象后面来实现。

Serde还有有关反序列化器生命周期的全面页面。它提到您也可以选择使用DeserializeOwned

trait Storable: Serialize + DeserializeOwned { /* ... */ }

你可以使用与DeserializeOwned相同的概念来创建自己的特质:
trait StorableOwned: for<'de> Storable<'de> { }

fn put<'de, S: StorableOwned>(obj: &'de S) -> Result<(), String> {

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接