在一个涉及自定义Serde(1.0)序列化和反序列化方法的项目中,我依靠这个测试 routine 来判断序列化一个对象并返回是否会产生一个等价的对象.

// let o: T = ...;
let buf: Vec<u8> = to_vec(&o).unwrap();
let o2: T = from_slice(&buf).unwrap();
assert_eq!(o, o2);

内联操作非常有效.我朝着可重用性迈出的下一步是为此制作一个function check_serde.

pub fn check_serde<T>(o: T)
where
    T: Debug + PartialEq<T> + Serialize + DeserializeOwned,
{
    let buf: Vec<u8> = to_vec(&o).unwrap();
    let o2: T = from_slice(&buf).unwrap();
    assert_eq!(o, o2);
}

这适用于拥有类型,但不适用于具有生存期界限(Playground)的类型:

check_serde(5);
check_serde(vec![1, 2, 5]);
check_serde("five".to_string());
check_serde("wait"); // [E0279]

错误是:

error[E0279]: the requirement `for<'de> 'de : ` is not satisfied (`expected bound lifetime parameter 'de, found concrete lifetime`)
  --> src/main.rs:24:5
   |
24 |     check_serde("wait"); // [E0277]
   |     ^^^^^^^^^^^
   |
   = note: required because of the requirements on the impl of `for<'de> serde::Deserialize<'de>` for `&str`
   = note: required because of the requirements on the impl of `serde::de::DeserializeOwned` for `&str`
   = note: required by `check_serde`

由于我希望使函数能够处理这些情况(包括带有字符串片段的 struct ),我try 了一个具有显式对象反序列化生存期的新版本:

pub fn check_serde<'a, T>(o: &'a T)
where
    T: Debug + PartialEq<T> + Serialize + Deserialize<'a>,
{
    let buf: Vec<u8> = to_vec(o).unwrap();
    let o2: T = from_slice(&buf).unwrap();
    assert_eq!(o, &o2);
}

check_serde(&5);
check_serde(&vec![1, 2, 5]);
check_serde(&"five".to_string());
check_serde(&"wait"); // [E0405]

这个实现会导致另一个问题,它不会编译(Playground).

error[E0597]: `buf` does not live long enough
  --> src/main.rs:14:29
   |
14 |     let o2: T = from_slice(&buf).unwrap();
   |                             ^^^ does not live long enough
15 |     assert_eq!(o, &o2);
16 | }
   | - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 10:1...
  --> src/main.rs:10:1
   |
10 | / pub fn check_serde<'a, T>(o: &'a T)
11 | |     where T: Debug + PartialEq<T> + Serialize + Deserialize<'a>
12 | | {
13 | |     let buf: Vec<u8> = to_vec(o).unwrap();
14 | |     let o2: T = from_slice(&buf).unwrap();
15 | |     assert_eq!(o, &o2);
16 | | }
   | |_^

我已经预料到了这一点:这个版本意味着序列化的内容(以及反序列化的对象)与输入对象一样存在,这是不正确的.缓冲区只能在函数的作用域内存在.

我的第三次try 试图构建原始输入的自有版本,从而避免使用具有不同生存期边界的反序列化对象的问题.ToOwned特性似乎适合这个用例.

pub fn check_serde<'a, T: ?Sized>(o: &'a T)
where
    T: Debug + ToOwned + PartialEq<<T as ToOwned>::Owned> + Serialize,
    <T as ToOwned>::Owned: Debug + DeserializeOwned,
{
    let buf: Vec<u8> = to_vec(&o).unwrap();
    let o2: T::Owned = from_slice(&buf).unwrap();
    assert_eq!(o, &o2);
}

这使得该函数现在可以用于普通字符串切片,但不能用于包含它们的复合对象(Playground):

check_serde(&5);
check_serde(&vec![1, 2, 5]);
check_serde(&"five".to_string());
check_serde("wait");
check_serde(&("There's more!", 36)); // [E0279]

同样,我们偶然发现了与第一个版本相同的错误:

error[E0279]: the requirement `for<'de> 'de : ` is not satisfied (`expected bound lifetime parameter 'de, found concrete lifetime`)
  --> src/main.rs:25:5
   |
25 |     check_serde(&("There's more!", 36)); // [E0279]
   |     ^^^^^^^^^^^
   |
   = note: required because of the requirements on the impl of `for<'de> serde::Deserialize<'de>` for `&str`
   = note: required because of the requirements on the impl of `for<'de> serde::Deserialize<'de>` for `(&str, {integer})`
   = note: required because of the requirements on the impl of `serde::de::DeserializeOwned` for `(&str, {integer})`
   = note: required by `check_serde`

当然,我很茫然.我们如何使用Serde构建一个通用函数来序列化一个对象并将其反序列化回一个新对象?特别是,这个函数可以在Rust(稳定或夜间)中实现吗?如果可以,我的实现缺少哪些调整?

推荐答案

不幸的是,您需要的是一个尚未在Rust中实现的特性:泛型关联类型.

让我们看看check_serde的另一个变体:

pub fn check_serde<T>(o: T)
where
    for<'a> T: Debug + PartialEq<T> + Serialize + Deserialize<'a>,
{
    let buf: Vec<u8> = to_vec(&o).unwrap();
    let o2: T = from_slice(&buf).unwrap();
    assert_eq!(o, o2);
}

fn main() {
    check_serde("wait"); // [E0279]
}

这里的问题是o2不能是T类型:o2buf,这是一个局部变量,但类型参数不能推断为受限制于函数体的生存期约束的类型.我们希望T在特定的生命周期内成为&strwithout.

对于泛型关联类型,这可以通过以下方式解决(显然我无法测试它,因为它尚未实现):

trait SerdeFamily {
    type Member<'a>: Debug + for<'b> PartialEq<Self::Member<'b>> + Serialize + Deserialize<'a>;
}

struct I32Family;
struct StrFamily;

impl SerdeFamily for I32Family {
    type Member<'a> = i32; // ignoring a parameter is allowed
}

impl SerdeFamily for StrFamily {
    type Member<'a> = &'a str;
}

pub fn check_serde<'a, Family>(o: Family::Member<'a>)
where
    Family: SerdeFamily,
{
    let buf: Vec<u8> = to_vec(&o).unwrap();
    // `o2` is of type `Family::Member<'b>`
    // with a lifetime 'b different from 'a
    let o2: Family::Member = from_slice(&buf).unwrap();
    assert_eq!(o, o2);
}

fn main() {
    check_serde::<I32Family>(5);
    check_serde::<StrFamily>("wait");
}

Rust相关问答推荐

阻止websocket中断的中断中断的终端(操作系统错误4)

关于Rust 中回归的逻辑

无法实现整型类型的泛型FN

如何在嵌套的泛型 struct 中调用泛型方法?

由于生存期原因,返回引用的闭包未编译

在 Rust 中,在需要引用 self 的 struct 体方法中使用闭包作为 while 循环条件

为什么我必须使用 PhantomData?在这种情况下它在做什么?

为什么 Rust 创建的 f32 小于 f32::MIN_POSITIVE?

在 Rust 中,是否可以定义一个需要实现类型的构造函数的对象安全特征?

Boxing 如何将数据从堆栈移动到堆?

`tokio::pin` 如何改变变量的类型?

枚举的利基优化如何在 Rust 中工作?

如何递归传递闭包作为参数?

错误:将自定义 proc_macro 与用Rust 的宝贝编写的属性一起使用时,无法在此范围内找到属性

在构建器模式中捕获 &str 时如何使用生命周期?

如何将参数传递给Rust 的线程?

仅当满足外部条件时如何添加到 actix web 的路由

我如何将特征作为 struct 的拥有字段?

为什么 no_std crate 可以依赖于使用 std 的 crate?

有没有更好的方法来为拥有 DIsplay 事物集合的 struct 实现 Display?