我正在尝试#[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
即可。