英文:
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<'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(("Failed to load: ".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::<GasParticleSystemSettings>(
&std::fs::read_to_string("assets/settings/gas_ps_settings.ron").unwrap()
).expect("Failed to load settings/gas_ps_settings.ron")
.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<'a>
时,反序列化的对象可能包含对原始str
的引用,类似这样的情况:
struct HasRef<'a> {
s: &'a str,
}
这是允许的。它将包含对在函数结束时被丢弃的ron_string
的引用。
然而,完全安全的方法是要求使用DeserializeOwned
,在这种情况下,您不能再进行零拷贝反序列化,但也不必保留原始字符串:
pub trait RonResource<T: de::DeserializeOwned + 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(("Failed to load: ".to_owned() + path).as_str())
}
}
您的第二个示例可能有效,因为您只访问了GasParticleSystemSettings.side_gas
,我假设它要么不包含引用,要么直接是Copy
,这两种情况都不会创建生命周期问题。
英文:
The problem is when using Deserialize<'a>
the deserialized object might contain references to the original str
ie something like this:
struct HasRef<'a> {
s: &'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<T: de::DeserializeOwned + 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(("Failed to load: ".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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论