Trong một dự án có các phương thức serialization và deserialization Serde (1.0) tùy chỉnh, tôi đã dựa vào thói quen kiểm tra này để kiểm tra xem serializing một đối tượng và ngược lại có mang lại một đối tượng tương đương hay không.Làm thế nào chúng ta có thể viết một chức năng chung để kiểm tra serde serialization và deserialization?
// let o: T = ...;
let buf: Vec<u8> = to_vec(&o).unwrap();
let o2: T = from_slice(&buf).unwrap();
assert_eq!(o, o2);
Làm nội tuyến này hoạt động khá tốt. Bước tiếp theo của tôi hướng tới khả năng sử dụng lại là tạo một hàm check_serde
cho mục đích này.
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);
}
này hoạt động tốt cho việc sở hữu các loại, nhưng không phải với nhiều loại với giới hạn tuổi thọ (Playground):
check_serde(5);
check_serde(vec![1, 2, 5]);
check_serde("five".to_string());
check_serde("wait"); // [E0279]
Lỗi:
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`
Như tôi muốn thực hiện các công việc chức năng với những trường hợp này (bao gồm các cấu trúc có lát cắt chuỗi), tôi đã thử một phiên bản mới với thời gian tồn tại của đối tượng deserialization:
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]
Triển khai này dẫn đến một vấn đề khác và nó sẽ không biên dịch (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 | | }
| |_^
Tôi đã mong đợi này: phiên bản này ngụ ý rằng các nội dung theo bộ (và do đó các đối tượng deserialized) sống miễn là đối tượng đầu vào, đó là không đúng sự thật. Bộ đệm chỉ có nghĩa là sống miễn là phạm vi của hàm.
Nỗ lực thứ ba của tôi tìm cách xây dựng các phiên bản thuộc sở hữu của đầu vào gốc, do đó tránh được vấn đề có đối tượng được deserialized với các giới hạn tuổi thọ khác nhau. Các đặc tính ToOwned
xuất hiện cho phù hợp với trường hợp sử dụng này.
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);
}
Điều này làm cho công việc chức năng cho đồng bằng chuỗi lát bây giờ, nhưng không cho các đối tượng hỗn chứa chúng (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]
Một lần nữa, chúng ta vấp ngã khi loại lỗi tương tự như phiên bản đầu tiên:
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`
Được cấp, tôi đang thua lỗ. Làm thế nào chúng ta có thể xây dựng một chức năng chung chung, bằng cách sử dụng Serde, serializes một đối tượng và deserializes nó trở lại vào một đối tượng mới? Đặc biệt, chức năng này có thể được thực hiện trong Rust (ổn định hoặc hàng đêm), và nếu có, những điều chỉnh nào để triển khai của tôi bị thiếu?