具有自定义数据类型的结构化

发布于 2025-01-26 13:00:03 字数 890 浏览 4 评论 0 原文

我正在尝试#[derive(deleialize,serialialize)] 一些涉及其他自定义结构的结构,因此我可以在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,
}

…但是我遇到了这个:

错误[E0495]:由于要求相互冲突,我无法推断出适当的寿命'de

我已经在线尝试了多个不同的解决方案,包括定义终身,我都在但是成功了。

我的所有代码都是在这里(对不起,Spaghetti)。有问题的文件是

I am trying to #[derive(Deserialize, Serialize)] some structs that involve other custom structs, so I can transform them in and out of JSON, for example:

#[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,
}

…but I am running into this:

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

I've tried multiple different solutions online, including defining lifetimes and I've all but succeeded.

All of my code is here (sorry for spaghetti). The file in question is exercises.rs.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

青巷忧颜 2025-02-02 13:00:04

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

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!()
    }
}

如您所见,只有在原始代码中的 innity struct( exerSize )才能在deSerializer(即源数据)是'静态,但是 ofert struct(原始代码中的 setEntry )已为每个deSerializer实现了其供应序列化生命周期 - 从本质上讲,它实现了 deerializewanded ,即它不需要从任何地方借入数据。

现在您可能会问,为什么这个限制性?为什么在第一种情况下 deSerializer&lt;'static&gt; ?答案是 - 您要求这样做,当放置 serde(borrow) &amp;'static str
当含有参考的构造结构时,Serde必须证明这些参考将永远不会悬空。因此,必须将必需数据的寿命(即 delelialize 特征)与原始数据的寿命相关联 - 即 Deserializer 的参数。而且,如果结构对其内容的寿命有任何限制,则这些限制会自动转移到 deserializer
在这种情况下,您已经要求提供最严格的限制 - 您已要求将被序列化的数据归为 innine 可用,直到程序结束为止。但是,对 ofter > - 实际上,它可以将 Inner 视为拥有的数据,因为该结构根本没有任何终身参数,因此询问最通用的求职者,然后当 Inner 要求它为'static 时,然后窒息。


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

首先,您绝对不想在任何运行时生成的数据中使用''static str 。这是字符串文字的类型,即融入可执行文件本身的字符串,而不是通用案例的字符串。

最简单,可能最正确的方法是将任何'''static str 替换为拥有的 String 。这将消除对 serde(borrow)的需求,并使您可以从任何东西中构建构造。

但是,如果您要使用参考(例如消除不必要的副本),则必须将整个结构树视为临时借入的求职者 - 也就是说,您将拥有与&amp有关的寿命参数; str 在每个直接或间接包含&amp; 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>,
}

然后,当用字符串文字手动创建这些结构时,您只需替换'static 对于'a

Minimized example which yields the same error:

use serde::Deserialize;

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

#[derive(Deserialize)]
pub struct Outer {
    pub inner: Inner,
}

Playground

To see what's wrong, let's look at the expanded code. It's rather large and not very readable, but even the signatures can help:

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!()
    }
}

As you can see, the Inner struct (the Exersize in original code) can be deserialized only when the deserializer (i.e. the source data) is 'static, but the Outer struct (the SetEntry in original code) has its deserialization implemented for every deserializer lifetime - essentially, it implements DeserializeOwned, i.e. it doesn't need to borrow its data from anywhere.

Now you might ask, why this restricton? Why the Deserializer<'static> in the first case? The answer is - you asked for that, when placed serde(borrow) over &'static str.
When deserializing struct containing references, Serde has to prove that these references will never be dangling. Therefore, the lifetime of deserialized data (that is, the parameter to Deserialize trait) must be tied to the lifetime of original data - that is, to the parameter of Deserializer. And, if the struct has any restrictions on the lifetime of its contents, these restrictions are automatically transferred to the Deserializer.
In this case, you've asked for the strictest restriction possible - you've asked that the data being deserialized into Inner be available until the end of program. However, there's no such restriction on Outer - in fact, it can treat Inner as owned data, since this struct doesn't have any lifetime parameters at all, - so Serde asks for the most generic deserializer possible and then chokes when Inner requires it to be 'static.


Now, what to do in this case?

First of all, you definitely don't want to use &'static str in any runtime-generated data. This is the type of string literals, i.e. of strings baked into the executable itself, not of the common-case strings.

The simplest and probably most correct way would be to replace any &'static str with the owned String. This will eliminate the need for serde(borrow) and make you struct deserializable from anything.

If, however, you want to use references (e.g. to eliminate unnecessary copies), you have to treat the whole structs tree as a temporary borrow into the deserializer - that is, you'll have the lifetime parameter tied to the &str in every struct which directly or indirectly contains that &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>,
}

And then, when creating these structs manually with string literals inside, you can just substitute 'static for 'a.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文