首先有个 AppConfig
#[derive(Deserialize, Clone, Debug)]
pub struct AppConfig {
pub listen: String
}
然后通过这个函数读取配置:
use std::fs::read_to_string;
use serde::Deserialize;
/// 读取配置文件
///
/// 读取来自 res/config/app.toml 的配置文件
pub fn get_app_config() -> AppConfig {
let read = read_to_string("res/config/app.toml");
match read {
Ok(text) => {
let toml: Result<AppConfig, toml::de::Error> = toml::from_str(text.as_str());
match toml {
Ok(v) => v,
Err(e) => {
println!("配置解析失败: {}", e.to_string());
exit(1);
}
}
},
Err(e) => {
println!("读取配置文件失败: {}", e.to_string());
exit(1);
}
}
}
以上代码运行一切正常。
我想写一个通用一点的函数,传入 struct 和文件名就可以读取到配置即可,于是写了这个
pub fn read_config<'a, T>(filename: &str) -> Result<T, String>
where
T: Deserialize<'a>,
{
let tr = read_to_string(format!("res/config/{}", filename));
match tr {
Ok(text) => {
println!("{}", text);
let tt: Result<T, toml::de::Error> = toml::from_str(text.as_str());
match tt {
Ok(t) => Ok(t),
Err(e) => Err(e.to_string())
}
},
Err(e) => Err(e.to_string())
}
}
然后我把 get_app_config 替换成了
pub fn get_app_config() -> AppConfig {
read_config::<AppConfig>("app.toml").unwrap()
}
结果就这样了
error[E0597]: `text` does not live long enough
--> src\base\app.rs:47:65
|
39 | pub fn read_config<'a, T>(filename: &str) -> Result<T, String>
| -- lifetime `'a` defined here
...
47 | let tt: Result<T, toml::de::Error> = toml::from_str(text.as_str());
| ---------------^^^^----------
| | |
| | borrowed value does not live long enough
| argument requires that `text` is borrowed for `'a`
...
52 | },
| - `text` dropped here while still borrowed
这是什么鬼设定???具体哪里有区别吗??
1
共 9 条评论, 1 页
评论区
写评论lz可以了解一下零拷贝这个概念,核心想法就是,比如这串json字符串已经读到了内存中的一个地方:
现在我要拿到hello字段的值,通常的做法就是复制一份"word"到内存的另一个地方,但如果你只是使用这个值而不会去修改它的话,更快捷的方法就是只引用(!)原本json字符串中的这一块,这样就省去了内存拷贝。
我是这样理解的,关键在于返回值T是
T: Deserialize<'a>
含声明周期的对象。 再看toml::from_str的签名:补充上生命周期应该是:
这就要求参数s的生命周期不能比T短。 text在read_config方法结束后就销毁了,所以就报错了。
恩,你的意思我明白,但是这个 text 传递给 toml 解析后理应已经变为另一个对象,已经不对原 text 持有任何所谓的引用了,这就好像比传递一个字符串给某个函数解析成 JSON 对象,结果这个 JSON 对象居然还引用着原来的那个字符串,理论上 JSON 对象应该跟原来的字符串没有任何关系了。
--
👇
rock117: 函数内部不能自己生成引用类型的数据并返回,这样函数体执行完,引用指向的内存就被释放了,这就是悬垂指针了,类比下c语言。返回的引用必须是直接或者间接基于函数参数产生的。
函数内部不能自己生成引用类型的数据并返回,这样函数体执行完,引用指向的内存就被释放了,这就是悬垂指针了,类比下c语言。返回的引用必须是直接或者间接基于函数参数产生的。
谢谢,被生命周期这个折腾的实在不轻,虽然可以运行了,但是看了这个 DeserializeOwned 的源码,还是很蒙圈。 还是得多看看。 。
--
👇
laizy: 因为你尝试将文件读出来的局部变量的数据借给T返回,自然要报错了,签名改成下面的:
--
👇
pader: 重点是写法相同,前面的就能正常运行,后面的无非就是换了个泛型,加了个生命周期?我也没看到具体哪里产生了影响。。。
因为你尝试将文件读出来的局部变量的数据借给T返回,自然要报错了,签名改成下面的:
--
👇
pader: 重点是写法相同,前面的就能正常运行,后面的无非就是换了个泛型,加了个生命周期?我也没看到具体哪里产生了影响。。。
重点是写法相同,前面的就能正常运行,后面的无非就是换了个泛型,加了个生命周期?我也没看到具体哪里产生了影响。。。
试过了,还是一样。。
--
👇
Neutron3529: 试试let xxxxxx=test.as_str()然后把xxxxxx送进函数
具体原理不清楚,但这样的确有效
或许是生命周期的问题
试试let xxxxxx=test.as_str()然后把xxxxxx送进函数
具体原理不清楚,但这样的确有效
或许是生命周期的问题