正在反序列化具有自定义数据类型的结构



我正在尝试#[derive(Deserialize, Serialize)]一些涉及其他自定义结构的结构,这样我就可以在JSON中转换它们,例如:

#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
pub struct Exercise {
#[serde(borrow)]
pub name: &'static str,
pub muscle_sub_groups: [MuscleSubGroup; 2],
pub recommended_rep_range: [u32; 2],
pub equipment: EquipmentType,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SetEntry {
pub exercise: Exercise,
pub reps: u32,
pub weight: Weight, // another struct with two: &'static str
pub reps_in_reserve: f32,
}

…但我遇到了这个:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter'dedue to conflicting requirements

我在网上尝试了多种不同的解决方案,包括定义寿命,我几乎都成功了。

我所有的代码都在这里(对不起意大利面条)。有问题的文件是exercises.rs.

产生相同错误的最小化示例:

use serde::Deserialize;
#[derive(Deserialize)]
pub struct Inner {
#[serde(borrow)]
pub name: &'static str,
}
#[derive(Deserialize)]
pub struct Outer {
pub inner: Inner,
}

游乐场

要了解问题所在,让我们看看扩展后的代码。它相当大,可读性不强,但即使是签名也有帮助:

impl Deserialize<'static> for Inner {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'static>,
{
todo!()
}
}
impl<'de> Deserialize<'de> for Outer {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
todo!()
}
}

如您所见,只有当解串器(即源数据)为'static时,才能对Inner结构体(原始代码中的Exersize)进行解串,但Outer结构体(原代码中的SetEntry)在每个解串器生命周期都实现了解串-本质上,它实现了DeserializeOwned,即不需要从任何地方借用数据。

现在你可能会问,为什么会有这种限制?为什么Deserializer<'static>在第一种情况下?答案是——当把serde(borrow)放在&'static str之上时,你要求这样做
当反序列化包含引用的结构时,Serde必须证明这些引用永远不会悬空。因此,反序列化数据的寿命(即Deserialize特性的参数)必须与原始数据的寿命绑定,即与Deserializer的参数绑定。并且,如果结构对其内容的生存期有任何限制,这些限制将自动转移到Deserializer
在这种情况下,您要求尽可能严格的限制——您要求反序列化为Inner的数据在程序结束前都可用。然而,对Outer没有这样的限制-事实上,它可以将Inner视为拥有的数据,因为这个结构根本没有任何生存期参数,所以Serde要求尽可能使用最通用的解串器,然后在Inner要求其为'static时阻塞。


现在,在这种情况下该怎么办?

首先,您绝对不希望在任何运行时生成的数据中使用&'static str。这是字符串文字的类型,即烘焙到可执行文件本身的字符串,而不是普通大小写字符串。

最简单也可能是最正确的方法是用所拥有的String替换任何&'static str。这将消除对serde(borrow)的需要,并使您的结构可以从任何东西反序列化。

然而,如果您想使用引用(例如,消除不必要的副本),您必须将整个结构树视为反序列化程序的临时借用-也就是说,您将在直接或间接包含&str:的每个结构中,将生存期参数绑定到&str

use serde::Deserialize;
#[derive(Deserialize)]
pub struct Inner<'a> {
#[serde(borrow)]
pub name: &'a str,
}
#[derive(Deserialize)]
pub struct Outer<'a> {
#[serde(borrow)]
pub inner: Inner<'a>,
}

然后,当手动创建这些包含字符串文字的结构时,只需将'a替换为'static即可。

相关内容

  • 没有找到相关文章

最新更新