简体   繁体   English

Rust结构不能替换HashMap中的trait

[英]Rust struct can't replace trait in HashMap

I'm trying to create a HashMap containing a known value for a specific input. 我正在尝试创建一个包含特定输入的已知值的HashMap This input can accept multiple types, as long as they implement a certain trait. 此输入可以接受多种类型,只要它们实现某种特征即可。 In this case, however, only a certain type is given, which Rust doesn't like. 但是,在这种情况下,只给出了某种类型,Rust不喜欢这种类型。

Is there any way to "convert" a struct into a trait, or otherwise fix this issue? 有没有办法将结构“转换”为特征,或以其他方式解决这个问题?

#![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);
}

The standard solution to this problem would be to use trait objects instead of generics. 这个问题的标准解决方案是使用特征对象而不是泛型。 Specifically, RedoxReaction would be defined as: 具体来说, RedoxReaction将定义为:

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

However, that doesn't work here because neither PartialEq , Eq nor Hash are object safe . 但是,这在这里PartialEq ,因为PartialEqEqHash都不是对象安全的 Indeed, it doesn't make a lot of sense to ask if two Elements are equal when one of them is an Ion and the other is a Photon . 实际上,当其中一个是Ion而另一个是Photon时,询问两个Elements是否相等并没有多大意义。

I would instead recommend that you consider using an enum for your elements. 我建议您考虑为元素使用枚举 All your elements would have the same type (the enum Element ), and object safety would not be an issue. 所有元素都具有相同的类型(枚举Element ),对象安全性不会成为问题。

I eventually solved this problem by using the hash of the Reaction as the key of the HashMap with the following function: 我最终通过使用Reaction哈希作为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()
}

Then you can use map.insert(reaction_to_hash(&reaction), <value>) to store the values, and map.get(& reaction_to_hash(&reaction)) to retrieve the value. 然后您可以使用map.insert(reaction_to_hash(&reaction), <value>)来存储值,并使用map.get(& reaction_to_hash(&reaction))来检索值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM