Reputation: 897
How does the the <From>
trait know which type to convert to in different contexts if it's implemented for more than one type?
For example, i have three types that have some mutual conversions implemented. On Character
i implement From
for both Token
and AminoAcid
. Yet, when i call .into()
in the hashmap i don't have to specify which type is required by the map's type definition. How is the trait aware of the context?
#[derive(Debug)]
struct Coordinate{
x:f64, y:f64, z:f64
}
#[derive(Debug)]
enum AminoAcid {
VAL, GLN ,ARG,...
}
#[derive(Debug)]
enum Token {
Coordinate(Coordinate),
AminoAcid(AminoAcid),
Character(Character)
}
impl From<Coordinate> for Token {
fn from(coord: Coordinate) -> Self {
Self::Coordinate(coord)
}
}
impl From<AminoAcid> for Token {
fn from(aa: AminoAcid) -> Self {
Self::AminoAcid(aa)
}
}
// ------------------------------------------------- <<<<
impl From<Character> for Token {
fn from(c: Character) -> Self {
Self::Character(c)
}
}
impl From<Character> for AminoAcid {
fn from(c: Character) -> Self {
Self::ALA
}
}
// ------------------------------------------------- <<<<
lazy_static! {
static ref HASHMAP: HashMap<&'static str, Token> = { // Here the value type is Token
let mut m = HashMap::new();
m.insert("ALA", Character::Second.into());
m
};
static ref HASHMAP: HashMap<&'static str, AminoAcid> = { // Here the value type is AminoAcid
let mut m = HashMap::new();
m.insert("ALA", Character::Second.into());
m
};
}
Upvotes: 1
Views: 325
Reputation: 16815
It's because Rust can deduce/infer types. For example
fn f1(arg: u8) {
println!("u8 in f1: {}", arg)
}
fn f2(arg: i64) {
println!("i64 in f2: {}", arg)
}
fn main() {
let a = 12;
let b = 23;
f1(a);
f2(b);
// f1(b); // expected `u8`, found `i64`
// f2(a); // expected `i64`, found `u8`
}
a
and b
are declared the same way; at this point, the compiler just knows they are some kind of integer.
At the first call of f1()
, since the expected argument is an u8
, Rust deduces that a
is actually an u8
.
The same goes for b
deduced as an i64
at the first usage of f2()
.
Of course, if after that we try to make the compiler deduce other types for these variables, it fails.
In your case, you declare your static bindings as hashmaps of a specific type: Token
in one case, AminoAcid
in the other.
Then, the brace used to initialise such a binding have to match this type; the type of the resulting expression (m
) is deduced accordingly.
The way we initialise m
expects the correct value type.
Consequently, the version of into()
providing this type is chosen.
Upvotes: 3
Reputation: 236
Because you defined the type of HASHMAP
, the compiler infers which type is needed, since if it converted into the other type it would not compile. https://doc.rust-lang.org/rust-by-example/types/inference.html
Upvotes: 0