【问题标题】:Rust struct can't replace trait in HashMapRust 结构不能替换 HashMap 中的 trait
【发布时间】:2017-03-18 16:55:54
【问题描述】:

我正在尝试创建一个HashMap,其中包含特定输入的已知值。这个输入可以接受多种类型,只要它们实现了某个特征。然而,在这种情况下,只给出了一个特定的类型,这是 Rust 不喜欢的。

有没有办法将结构“转换”为特征,或者解决这个问题?

#![allow(unused)]

use std::collections::HashMap;
use std::hash::*;


trait Element: Eq + PartialEq + Hash {}

trait Reaction<T: Element> {}


#[derive(Eq, Hash, PartialEq)]
struct Ion {
    charge: u16
}

impl Element for Ion {}


#[derive(Eq, Hash, PartialEq)]
struct RedoxReaction<T: Element> { left: T }

impl<T: Element> Reaction<T> for RedoxReaction<T> {}


fn get_sep_database<T: Element>() -> HashMap<RedoxReaction<T>, f32> {
    let mut map: HashMap<RedoxReaction<T>, f32> = HashMap::new();

    let reaction = RedoxReaction {
        left: Ion {
            charge: 1
        }
    };

    // note: expected type `RedoxReaction<T>`
    //       found type `RedoxReaction<Ion>`
    map.insert(reaction, 0.000 as f32);

    return map;
}


fn main() {
    let db = get_sep_database();

    let reaction = RedoxReaction {
        left: Ion {
            charge: 1
        }
    };

    // expected this to be 0.000
    let sep = db.get(&reaction);
}

【问题讨论】:

    标签: struct rust traits


    【解决方案1】:

    这个问题的标准解决方案是使用 trait 对象 而不是泛型。具体来说,RedoxReaction 将被定义为:

    #[derive(Eq, Hash, PartialEq)]
    struct RedoxReaction { left: Box<Element> }
    

    但是,这在这里不起作用,因为 PartialEqEqHash 都不是 object safe。事实上,当两个Elements 一个是Ion 而另一个是Photon 时,问两个Elements 是否相等并没有多大意义。

    我建议您考虑为您的元素使用enum。您的所有元素都将具有相同的类型(枚举 Element),并且对象安全不会成为问题。

    【讨论】:

    • 感谢您的回答。但是,正如您可能猜到的,我还想在运行时创建新的Elements(在本例中为Molecules)。我不确定枚举是否(以及如何)可能。现在,我将看看如何更改我的代码。
    • 这样看:对于每个将实现 Element 特征的结构,您改为向 Element 枚举添加一个变体。在 Rust 中,你不能在运行时创建类型,也不能在运行时创建枚举变体,所以在这方面使用枚举而不是类型族应该不会妨碍你。
    【解决方案2】:

    我最终通过使用Reactionhash 作为HashMap 的键并具有以下功能解决了这个问题:

    use std::collections::hash_map::DefaultHasher;
    use std::hash::*;
    
    fn reaction_to_hash<E: Element>(reaction: &Reaction<E>) -> u64 {
        let mut s = DefaultHasher::new();
        reaction.hash(&mut s);
        s.finish()
    }
    

    然后您可以使用map.insert(reaction_to_hash(&amp;reaction), &lt;value&gt;) 存储值,并使用map.get(&amp; reaction_to_hash(&amp;reaction)) 检索值。

    【讨论】:

      猜你喜欢
      • 2021-05-08
      • 2017-11-03
      • 1970-01-01
      • 2017-05-27
      • 1970-01-01
      • 2021-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多