< 返回版块

Nayaka 发表于 2022-04-24 10:25

Tags:生命周期

生命周期的文章研究了不少,大概是因为本人确实愚钝,还是没有解决这个问题,求大佬来指条明路,万分感谢

use serde::{Deserialize, Serialize};
use std::path::PathBuf;

trait ReadFromFile {
    fn read_from_file<'a, T: Serialize>(path: &PathBuf) -> T
    where
        T: Deserialize<'a>
    {
        let v = std::fs::read_to_string(path).unwrap();
        serde_json::from_str(&v).unwrap()
    }
}

#[derive(Serialize, Deserialize, Debug)]
struct Server {
    username: String,
    password: String
}

#[derive(Serialize, Deserialize, Debug)]
struct Servers {
    servers: Server
}

impl ReadFromFile for Server {}

impl ReadFromFile for Servers {}

fn main() {
    let path = PathBuf::from("./servers.json");
    let _servers:Servers = Servers::read_from_file(&path);
    println!("hello");
}

playground的地址如下:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c94374bf27901541074821bf37dec401

评论区

写评论
litttley 2022-04-24 12:43

#[cfg(test)] mod tests { use std::path::PathBuf;

use serde::{Deserialize, Serialize};

trait ReadFromFile {
    fn read_from_file<'a, T: Serialize>(v: &'a std::string::String) -> T
    where
        T: Deserialize<'a>,
    {
        // let v = std::fs::read_to_string(path).unwrap();
        serde_json::from_str(v).unwrap()
    }
}

#[derive(Serialize, Deserialize, Debug)]
struct Server {
    username: String,
    password: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct Servers {
    servers: Server,
}

impl ReadFromFile for Server {}

impl ReadFromFile for Servers {}

#[test]
fn it_works() {
    let path = PathBuf::from("./servers.json");
    let v = std::fs::read_to_string(path).unwrap();
    // let json_ojb=None
    let _servers: Servers = Servers::read_from_file(&v);
}

}

作者 Nayaka 2022-04-24 11:47

你太客气了,还特意去看了一下,因为之前只是简单的用Serialize/Deserialize, 所以也没有想到引入DeserializeOwned

我再多去看一下,收获很多,再次感谢!

--
👇
Aya0wind: 不好意思,我又去试了一下,应该还是你生命周期标记的问题,直接使用from_str从String反序列化一个类型是会copy的。只是from_reader由于没有buffer效率较低,才会需要一个bufferreader。
所以问题并不在from_str,from_str是可以的,而是你把'a生命周期绑定到T上了,但是这里根本不需要’a,因为返回的T本身是不引用那个字符串v的,所以你应该这么写。

fn read_from_file<T:DeserializeOwned,P:AsRef<Path>>(path:P)->T{
    let v = std::fs::read_to_string(path).unwrap();
    serde_json::from_str::<T>(&v).unwrap()
}

--
👇
Nayaka: 十分感谢,刚刚参考 @Aya0wind 的回答,已经搞定了. 看了你的答案,对生命周期有了新的理解,再次感谢!

--
👇
Grobycn: 改成这样可以通过,可以理解为对于所有可能的生命周期'a, 都可以反序列化出一个T, T 已经不依赖于输入参数的生命周期 'a了。

trait ReadFromFile {
    fn read_from_file<T: Serialize>(path: &PathBuf) -> T
    where
        for<'a> T: Deserialize<'a>
    {
        let v = std::fs::read_to_string(path).unwrap();
        serde_json::from_str(&v).unwrap()
    }
}
Aya0wind 2022-04-24 11:43

不好意思,我又去试了一下,应该还是你生命周期标记的问题,直接使用from_str从String反序列化一个类型是会copy的。只是from_reader由于没有buffer效率较低,才会需要一个bufferreader。
所以问题并不在from_str,from_str是可以的,而是你把'a生命周期绑定到T上了,但是这里根本不需要’a,因为返回的T本身是不引用那个字符串v的,所以你应该这么写。

fn read_from_file<T:DeserializeOwned,P:AsRef<Path>>(path:P)->T{
    let v = std::fs::read_to_string(path).unwrap();
    serde_json::from_str::<T>(&v).unwrap()
}

--
👇
Nayaka: 十分感谢,刚刚参考 @Aya0wind 的回答,已经搞定了. 看了你的答案,对生命周期有了新的理解,再次感谢!

--
👇
Grobycn: 改成这样可以通过,可以理解为对于所有可能的生命周期'a, 都可以反序列化出一个T, T 已经不依赖于输入参数的生命周期 'a了。

trait ReadFromFile {
    fn read_from_file<T: Serialize>(path: &PathBuf) -> T
    where
        for<'a> T: Deserialize<'a>
    {
        let v = std::fs::read_to_string(path).unwrap();
        serde_json::from_str(&v).unwrap()
    }
}
作者 Nayaka 2022-04-24 11:37

十分感谢,刚刚参考 @Aya0wind 的回答,已经搞定了. 看了你的答案,对生命周期有了新的理解,再次感谢!

--
👇
Grobycn: 改成这样可以通过,可以理解为对于所有可能的生命周期'a, 都可以反序列化出一个T, T 已经不依赖于输入参数的生命周期 'a了。

trait ReadFromFile {
    fn read_from_file<T: Serialize>(path: &PathBuf) -> T
    where
        for<'a> T: Deserialize<'a>
    {
        let v = std::fs::read_to_string(path).unwrap();
        serde_json::from_str(&v).unwrap()
    }
}
Grobycn 2022-04-24 11:25

改成这样可以通过,可以理解为对于所有可能的生命周期'a, 都可以反序列化出一个T, T 已经不依赖于输入参数的生命周期 'a了。

trait ReadFromFile {
    fn read_from_file<T: Serialize>(path: &PathBuf) -> T
    where
        for<'a> T: Deserialize<'a>
    {
        let v = std::fs::read_to_string(path).unwrap();
        serde_json::from_str(&v).unwrap()
    }
}
作者 Nayaka 2022-04-24 11:18

之前想过from_reader,结果还是跟from_str杠上了,谢谢

--
👇
Aya0wind: 你看一下serde_json的文档,文档里提到:

The content of the IO stream is deserialized directly from the stream without being buffered in memory by serde_json.  
When reading from a source against which short reads are not efficient, such as a File, you will want to apply your own buffering because serde_json will not buffer the input. See std::io::BufReader.

所以serde_json的from_str是直接在输入的str上原地构造的,所以你引用一个局部的String,返回之后String就没了,所以你返回反序列化的结果就指向无效内存了。
至于正确写法,serde_json的文档里有一个和你这个功能一模一样的例子,你可以看看应该怎么做 serde_json::from_reader

Aya0wind 2022-04-24 11:05

你看一下serde_json的文档,文档里提到:

The content of the IO stream is deserialized directly from the stream without being buffered in memory by serde_json.  
When reading from a source against which short reads are not efficient, such as a File, you will want to apply your own buffering because serde_json will not buffer the input. See std::io::BufReader.

所以serde_json的from_str是直接在输入的str上原地构造的,所以你引用一个局部的String,返回之后String就没了,所以你返回反序列化的结果就指向无效内存了。
至于正确写法,serde_json的文档里有一个和你这个功能一模一样的例子,你可以看看应该怎么做 serde_json::from_reader

1 共 7 条评论, 1 页