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

问题描述 投票:0回答:1

我无法使用以下代码(游乐场: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);
}

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

我现在想要一个 OuterStruct,它是一个通用容器,可以容纳任何类型的内部结构。如果我不应用任何特征界限,它工作正常,但是当我尝试应用特征界限时,说这个结构只对 T 有效,因为 InnerStruct 一切都会中断。编译器消息谈论生命周期,但没有一个建议有效。

一个具体的例子:对于

struct OuterStruct<T: InnerStruct> {

编译器建议

help: consider introducing a named lifetime parameter
   |
23 | struct OuterStruct<'a, T: InnerStruct<'a>> {

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

error[E0392]: parameter `'a` is never used
  --> src/main.rs:23:20
   |
23 | struct OuterStruct<'a, T: InnerStruct<'a>> {
   |                    ^^ unused parameter

我做错了什么?

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

note: multiple `impl`s or `where` clauses satisfying `T: Deserialize<'_>` found
rust traits lifetime serde
1个回答
0
投票

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

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

#[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());
}

游乐场链接


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

trait InnerStruct: DeserializeOwned + Serialize {}

...

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

游乐场链接

您的原始代码无法正常工作,因为您对结构有限制;并且

#[derive(Deserialize)]
宏正在将绑定复制到其
impl<'a> Deserialize<'a> for
结构上,而且还添加了一个
T: Deserialize<'a>
绑定。通常
T:
界限是必要的,但在这种情况下,我猜 Rust 不喜欢看到
T: Deserialize
以两种不同的方式被要求。所以解决方案是告诉宏不要在
T
.

上发出它通常的界限

serde(bound)
属性记录在here.

© www.soinside.com 2019 - 2024. All rights reserved.