Can't Deserialize in generic trait function due to lifetime issue, but it works when out of generic function

huangapple go评论59阅读模式
英文:

Can't Deserialize in generic trait function due to lifetime issue, but it works when out of generic function

问题

我想要实现一个特质函数,它接受一个路径并返回一个拥有的值。

```rust
use bevy::prelude::*;
use serde::de;

pub trait RonResource<'a, T: de::Deserialize<'a> + Resource> {
    fn import_from_ron(path: &str) -> T {

        let ron_string = std::fs::read_to_string(path).unwrap();

        ron::from_str::<T>(
                &ron_string
            ).expect("加载失败: ".to_owned() + path)
    }
}

我实现了 'a 生命周期,因为 de::Deserialize 需要它。
但编译器告诉我 "&ron_string" 将在仍然被借用的情况下被释放。(在 "&ron_string" 行)

如果我不使用泛型来实现这段代码,它可以正常工作,就像这样:

let settings = ron::from_str::<GasParticleSystemSettings>(
            &std::fs::read_to_string("assets/settings/gas_ps_settings.ron").unwrap()
        ).expect("加载失败 settings/gas_ps_settings.ron")
        .side_gas;

我不明白为什么这个值需要在整个函数中“存活”,因为它不会被需要。否则,特定的代码将无法工作!


<details>
<summary>英文:</summary>

I would like to implement a trait function that takes a path and gives an owned value.

```rust
use bevy::prelude::*;
use serde::de;

pub trait RonResource&lt;&#39;a, T: de::Deserialize&lt;&#39;a&gt; + Resource&gt; {
    fn import_from_ron(path: &amp;str) -&gt; T {

        let ron_string = std::fs::read_to_string(path).unwrap();

        ron::from_str::&lt;T&gt;(
                &amp;ron_string
            ).expect((&quot;Failed to load: &quot;.to_owned() + path).as_str())
    }
}

I implement the 'a lifetime because de::Deserialize needs it.
But the compiled tells me that "ron_string" will be dropped while still borrowed. (at the "&ron_string" line)

This code works fine if I implement it without generics, like this for exemple:

let settings = ron::from_str::&lt;GasParticleSystemSettings&gt;(
            &amp;std::fs::read_to_string(&quot;assets/settings/gas_ps_settings.ron&quot;).unwrap()
        ).expect(&quot;Failed to load settings/gas_ps_settings.ron&quot;)
        .side_gas;

I don't get why the value need to "survive" the whole function as it will not be needed. Otherwise, the specific code wouldn't work!

答案1

得分: 1

问题出在使用Deserialize&lt;&#39;a&gt;时,反序列化的对象可能包含对原始str的引用,类似这样的情况:

struct HasRef&lt;&#39;a&gt; {
    s: &amp;&#39;a str,
}

这是允许的。它将包含对在函数结束时被丢弃的ron_string的引用。

然而,完全安全的方法是要求使用DeserializeOwned,在这种情况下,您不能再进行零拷贝反序列化,但也不必保留原始字符串:

pub trait RonResource&lt;T: de::DeserializeOwned + Resource&gt; {
    fn import_from_ron(path: &amp;str) -&gt; T {
        let ron_string = std::fs::read_to_string(path).unwrap();

        ron::from_str::&lt;T&gt;(
                &amp;ron_string
            ).expect((&quot;Failed to load: &quot;.to_owned() + path).as_str())
    }
}

您的第二个示例可能有效,因为您只访问了GasParticleSystemSettings.side_gas,我假设它要么不包含引用,要么直接是Copy,这两种情况都不会创建生命周期问题。

英文:

The problem is when using Deserialize&lt;&#39;a&gt; the deserialized object might contain references to the original str ie something like this:

struct HasRef&lt;&#39;a&gt; {
    s: &amp;&#39;a str,
}

is allowed. It would contain references to ron_string which is dropped at the end of the function.

What's totally save though is to just require DeserializeOwned instead at which point you can't do 0-copy deserialization any more but you don't have to keep the original string around either:

pub trait RonResource&lt;T: de::DeserializeOwned + Resource&gt; {
    fn import_from_ron(path: &amp;str) -&gt; T {
        let ron_string = std::fs::read_to_string(path).unwrap();

        ron::from_str::&lt;T&gt;(
                &amp;ron_string
            ).expect((&quot;Failed to load: &quot;.to_owned() + path).as_str())
    }
}

Your second example works presumably because you only access GasParticleSystemSettings.side_gas which I assume either does not contain references or is straight up Copy neither of which would create a lifetime issue.

huangapple
  • 本文由 发表于 2023年2月16日 16:42:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/75469692.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定