如何为必须是 serde 可序列化的特征添加特征边界

Cor*_*one 1 traits lifetime rust serde

我无法让以下代码工作(游乐场:https://play.rust-lang.org/? version=stable&mode= debug&edition=2021&gist=4379c2006dcf3d32f59b0e44626ca667)。

use serde::{Serialize, Deserialize};

trait InnerStruct<'delife>: Deserialize<'delife> + Serialize {}

#[derive(Serialize, Deserialize)]
struct InnerStructA{
    a: i32
}

impl InnerStruct<'_> for InnerStructA {}

#[derive(Serialize, Deserialize)]
struct InnerStructB{
    a: i32,
    b: i32
}

impl InnerStruct<'_> for InnerStructB {}

#[derive(Serialize, Deserialize)]
struct OuterStruct<T: InnerStruct>{   // Remove the word "InnerStruct" and this works
    c: f64,
   inner: T
}

fn print_json<T: for<'a> InnerStruct<'a>>(obj: T) {
    println!("Serde JSON: {:?}", serde_json::to_string(&obj).unwrap());
}

fn main() {
    let inner_a = InnerStructA{a: 123};
    let inner_b = InnerStructB{a: 234, b: 567};

    println!("Serde JSON: {:?}", serde_json::to_string(&inner_a).unwrap());
    println!("Serde JSON: {:?}", serde_json::to_string(&inner_b).unwrap());
    
    print_json(inner_a);
    print_json(inner_b);
}
Run Code Online (Sandbox Code Playgroud)

我有一个可序列化的结构集合(InnerStructA、InnerStructA),它们都实现了一个特征。有些函数在统一它们的特征(InnerStruct)中是通用的。其中一些函数要求它们可序列化和反序列化,因此我已将 Deserialize 和 Serialize supertraits 添加到特征定义中。反序列化需要添加命名生命周期。

我现在想要一个 OuterStruct,它是一个通用容器,可以容纳任何类型的内部结构。如果我不应用任何特征边界,它就可以正常工作,但是当我尝试应用特征边界来表示该结构仅对 T 为 InnerStruct 有效时,一切都会中断。编译器消息讨论了生命周期,但所有建议都不起作用。

一个具体的例子:对于

use serde::{Serialize, Deserialize};

trait InnerStruct<'delife>: Deserialize<'delife> + Serialize {}

#[derive(Serialize, Deserialize)]
struct InnerStructA{
    a: i32
}

impl InnerStruct<'_> for InnerStructA {}

#[derive(Serialize, Deserialize)]
struct InnerStructB{
    a: i32,
    b: i32
}

impl InnerStruct<'_> for InnerStructB {}

#[derive(Serialize, Deserialize)]
struct OuterStruct<T: InnerStruct>{   // Remove the word "InnerStruct" and this works
    c: f64,
   inner: T
}

fn print_json<T: for<'a> InnerStruct<'a>>(obj: T) {
    println!("Serde JSON: {:?}", serde_json::to_string(&obj).unwrap());
}

fn main() {
    let inner_a = InnerStructA{a: 123};
    let inner_b = InnerStructB{a: 234, b: 567};

    println!("Serde JSON: {:?}", serde_json::to_string(&inner_a).unwrap());
    println!("Serde JSON: {:?}", serde_json::to_string(&inner_b).unwrap());
    
    print_json(inner_a);
    print_json(inner_b);
}
Run Code Online (Sandbox Code Playgroud)

编译器建议

struct OuterStruct<T: InnerStruct> {
Run Code Online (Sandbox Code Playgroud)

但这样做会导致另一个错误

help: consider introducing a named lifetime parameter
   |
23 | struct OuterStruct<'a, T: InnerStruct<'a>> {
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

编辑:DeserializeOwned 如果特征更改为 DeserializedOwned,那么生命周期问题就会消失,但问题仍然存在。这似乎与将导出(反序列化)应用于 OuterStruct 有关,该 OuterStruct 已经包含已应用导出(反序列化)的内容。错误信息是:

note: multiple `impl`s or `where` clauses satisfying `T: Deserialize<'_>` found
Run Code Online (Sandbox Code Playgroud)

Jas*_*rff 5

通常最好不要对结构或枚举设置任何不必要的界限。这样更灵活,尤其是在处理具有生命周期参数的特征时。

所以我会尝试这样的事情:

#[derive(Serialize, Deserialize)]
struct OuterStruct<T> {
    c: f64,
    inner: T,
}

fn print_json<'a, T>(obj: T)
where
    T: InnerStruct<'a>,
{
    println!("Serde JSON: {:?}", serde_json::to_string(&obj).unwrap());
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接


在您的示例程序中,这也将起作用:

trait InnerStruct: DeserializeOwned + Serialize {}

...

#[derive(Serialize, Deserialize)]
struct OuterStruct<T: InnerStruct> {
    c: f64,
    #[serde(bound(deserialize = ""))]
    inner: T,
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接

您的原始代码无法正常工作,因为您对结构有限制;宏#[derive(Deserialize)]将绑定复制到其impl<'a> Deserialize<'a> for结构上,同时还添加了一个T: Deserialize<'a>绑定。通常这个T:界限是必要的,但在这种情况下,我猜 Rust 不喜欢T: Deserialize以两种不同的方式看到需要。因此,解决方案是告诉宏不要在 上发出其通常的界限T

serde(bound)属性记录在此处