I'm trying to create a HashMap
containing a known value for a specific input. 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.
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:
#[derive(Eq, Hash, PartialEq)]
struct RedoxReaction { left: Box<Element> }
However, that doesn't work here because neither PartialEq
, Eq
nor Hash
are object safe . 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
.
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.
I eventually solved this problem by using the hash of the Reaction
as the key of the HashMap
with the following function:
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.