如何编写一个通用函数,该函数可用于反序列化TOML的多个输出类型?

时间:2018-10-05 14:01:48

标签: rust

我编写了一个实用程序方法,该方法可以从TOML文件创建配置对象:

pub fn read_common(path: &str) -> Result<Config> {
    let content = read_file(path);
    toml::from_str(&content?).map_err(|e| {
        Error::new(
            ErrorKind::InvalidData,
            format!(
                "Parsing failed at line {:?}, col {:?}",
                e.line_col().map(|p| p.0),
                e.line_col().map(|p| p.1)
            ),
        )
    })
}

Config是一个简单的可反序列化的结构:

#[derive(Deserialize)]
pub struct DatabaseConfig {
    pub host: String,
    pub port: u16,
    pub database: String,
    pub user: String,
    pub password: String,
}

#[derive(Deserialize)]
pub struct Config {
    pub database: DatabaseConfig,
}

这可以编译并正常运行(应该这样做,因为它几乎是从the toml crate's documentation复制粘贴而来的。)

我有多个配置文件,每个配置文件都具有对应的匹配结构,因此我想泛化我的read_common方法(在所有其他情况下重用相同的错误处理)。

我写了这个:

pub fn read<'de, T>(path: &str) -> Result<T>
where
    T: Deserialize<'de>,
{
    let content = read_file(path);
    toml::from_str(&content?).map_err(|e| {
        Error::new(
            ErrorKind::InvalidData,
            format!(
                "Parsing failed at line {:?}, col {:?}",
                e.line_col().map(|p| p.0),
                e.line_col().map(|p| p.1)
            ),
        )
    })
}

T是反序列化产生的配置类型。我需要将其扩展Deserialize<'..>,所以我需要在此处给出生命周期,但是toml::from_str的完整签名是

pub fn from_str<'de, T>(s: &'de str) -> Result<T, Error>
where
    T: de::Deserialize<'de>,

据我了解,我的输入字符串的寿命应与产生的反序列化对象的寿命相同(或更长)。自从它的生命周期在我的read方法结束时结束以来,它当然不在我的实现中。因此,借用检查器会抱怨(borrowed value does not live long enough on &content?,并且此实现无法编译。

我如何编写适用于多种输出类型的read的通用read_common版本?

我对此问题还有其他疑问:

  • read_common中的生存期会怎样?反序列化的字符串也是短暂的,该实现如何编译?我想#[derive(Deserialize)]中隐藏了一些技巧。
  • 为什么toml::from_str的输入变量和输出类型的寿命相同?对我来说,反序列化完成后,输出不应引用输入字符串,为什么方法声明中存在生命周期?

0 个答案:

没有答案