< 返回版块

pader 发表于 2020-08-13 11:28

首先有个 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

这是什么鬼设定???具体哪里有区别吗??

评论区

写评论
rock117 2020-09-19 00:17

函数内部不能自己生成引用类型的数据并返回,这样函数体执行完,引用指向的内存就被释放了,这就是悬垂指针了,类比下c语言。返回的引用必须是直接或者间接基于函数参数产生的。

作者 pader 2020-08-13 16:36

谢谢,被生命周期这个折腾的实在不轻,虽然可以运行了,但是看了这个 DeserializeOwned 的源码,还是很蒙圈。 还是得多看看。 。

--
👇
laizy: 因为你尝试将文件读出来的局部变量的数据借给T返回,自然要报错了,签名改成下面的:

pub fn read_config<T>(filename: &str) -> Result<T, String>
where
    T: DeserializeOwned,

--
👇
pader: 重点是写法相同,前面的就能正常运行,后面的无非就是换了个泛型,加了个生命周期?我也没看到具体哪里产生了影响。。。

laizy 2020-08-13 13:27

因为你尝试将文件读出来的局部变量的数据借给T返回,自然要报错了,签名改成下面的:

pub fn read_config<T>(filename: &str) -> Result<T, String>
where
    T: DeserializeOwned,

--
👇
pader: 重点是写法相同,前面的就能正常运行,后面的无非就是换了个泛型,加了个生命周期?我也没看到具体哪里产生了影响。。。

作者 pader 2020-08-13 12:40

重点是写法相同,前面的就能正常运行,后面的无非就是换了个泛型,加了个生命周期?我也没看到具体哪里产生了影响。。。

作者 pader 2020-08-13 12:39

试过了,还是一样。。

--
👇
Neutron3529: 试试let xxxxxx=test.as_str()然后把xxxxxx送进函数

具体原理不清楚,但这样的确有效

或许是生命周期的问题

Neutron3529 2020-08-13 12:37

试试let xxxxxx=test.as_str()然后把xxxxxx送进函数

具体原理不清楚,但这样的确有效

或许是生命周期的问题

1 共 6 条评论, 1 页