【问题标题】:Creating structures with references in Rust在 Rust 中创建具有引用的结构
【发布时间】:2021-05-14 09:56:12
【问题描述】:

我是 Rust 的新手,我一直在尝试使用它来解决一些优化问题。我的目标是解析一个包含问题实体信息的实例(在本例中为 JSON 字符串)。解析完实例后,我会得到一个结构,其中包含读取的所有不同类型的实体。

在下面的代码中,我设法读取了 JSON 字符串并遍历了一些实体。我尝试实现特征From,以便它可以从serde_json::Map 转换为Entity

use serde_json::{Map, Value};
use std::{collections::HashSet};

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct Entity<'a> {
    field1: u64,
    field2: &'a str,
}

impl <'a> Entity<'a> {
    fn read_entities(json_entities: &Value) -> HashSet<Entity> {
        let mut entities = HashSet::new();

        if json_entities.is_array() {
            let array = json_entities.as_array().unwrap();
            for item in array.iter() {
                entities.insert(Entity::from(item));
            }
        }

        entities
    }
}

impl <'a> From<&Map<String, Value>> for Entity<'a> {
    fn from(obj: &Map<String, Value>) -> Entity<'a> {
        Entity {
            field1: obj["Field1"].as_u64().unwrap(),
            field2: obj["Field2"].as_str().unwrap(),
        }
    }
}

#[derive(Debug)]
pub struct Data<'a> {
    entities: HashSet<Entity<'a>>,
}

impl <'a> Data<'a> {
    pub fn new() -> Data<'a> {
        let data = r#"{"Entities":[{"Field1":0,"Field2":"Abc"},{"Field1":1,"Field2":"Abc"}]}"#;
        let json: Value = serde_json::from_str(&data).expect("");
        let mut entities = Entity::read_entities(&json["Entities"]);
        Data {
            entities,
        }
    }
}

fn main() {
    let data = Data::new();
}

我一直在努力解决以下两个错误:

error[E0277]: the trait bound `Entity<'_>: From<&Value>` is not satisfied
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements

我对第一个错误的理解是我实现的特征是针对Entity&lt;'a&gt;,因此编译器无法调用Entity::from(item)。但是,我不知道应该在此通话中通知Entity 的生命周期'a。我觉得第二个错误是关于我应该将生命周期'a 放在哪里的类似问题。我已经为这两个错误苦苦挣扎了一段时间,但我自己无法弄清楚。

如果你能指出有什么不习惯的地方,我也很高兴。

【问题讨论】:

    标签: rust


    【解决方案1】:

    发布的代码存在很多问题,但大多数都归结为一个根本原因。

    如果您试图从代码中获得所有可能的性能,则传递生命周期并将&amp;str 用于字段将是合适的。但在这种情况下,它会阻碍你 - 而且 JSON 类型无论如何都不允许 - Value 枚举实际上包含 String 而不是 &amp;str,我认为这是因为 JSON 字符串转义规则。

    你到处都有&lt;'a&gt;的原因是因为你在Entity中使用&amp;str,而不是String

    下一个问题是你的From&amp;Map&lt;String, Value&gt;,而不是&amp;Value

    做出这两个改变我得到:

    use serde_json::Value;
    use std::collections::HashSet;
    
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct Entity {
        field1: u64,
        field2: String,
    }
    
    impl Entity {
        fn read_entities(json_entities: &Value) -> HashSet<Entity> {
            let mut entities = HashSet::new();
    
            if json_entities.is_array() {
                let array = json_entities.as_array().unwrap();
                for item in array.iter() {
                    entities.insert(Entity::from(item));
                }
            }
    
            entities
        }
    }
    
    impl From<&Value> for Entity {
        fn from(obj: &Value) -> Entity {
            Entity {
                field1: obj["Field1"].as_u64().unwrap(),
                field2: obj["Field2"].as_str().unwrap().to_string(),
            }
        }
    }
    
    #[derive(Debug)]
    pub struct Data {
        entities: HashSet<Entity>,
    }
    
    impl Data {
        pub fn new() -> Data {
            let data = r#"{"Entities":[{"Field1":0,"Field2":"Abc"},{"Field1":1,"Field2":"Abc"}]}"#;
            let json: Value = serde_json::from_str(&data).expect("");
            let entities = Entity::read_entities(&json["Entities"]);
            Data { entities }
        }
    }
    
    fn main() {
        let data = Data::new();
    }
    

    您可以在 playground 上找到它

    【讨论】:

    • 我的理解是您的解决方案仅适用于字符串。最终,我想在我的实体中引用结构。 Field2 可能是对不同实体类型的引用。例如,我可以从我的 JSON 字符串中解析品牌和商品的列表,并且每个商品都会引用一个品牌。在这种情况下,我应该如何进行?如果需要,我可以更新我的问题。
    猜你喜欢
    • 2021-10-24
    • 2023-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多