#rust
#Ржавчина
Вопрос:
Как <From>
признак узнает, в какой тип преобразовать в разных контекстах, если он реализован для более чем одного типа?
Например, у меня есть три типа, в которых реализованы некоторые взаимные преобразования. Character
Я реализую From
для обоих Token
и AminoAcid
. Тем не менее, когда я вызываю .into()
hashmap, мне не нужно указывать, какой тип требуется в определении типа карты. Как признак осознает контекст?
#[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<amp;'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<amp;'static str, AminoAcid> = { // Here the value type is AminoAcid
let mut m = HashMap::new();
m.insert("ALA", Character::Second.into());
m
};
}
Комментарии:
1. Я далеко не эксперт по Rust, но я почти уверен, что это из-за вывода типов —
.into()
вызовы здесь должны возвращать типы, которые они делают, потому что в противномinsert
случае вызовы не будут правильно типизированы, учитывая типы в HashMap, которые вы явно указали.
Ответ №1:
Это потому, что Rust может выводить / выводить типы. Например
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
и b
объявляются одинаково; на этом этапе компилятор просто знает, что они представляют собой какое-то целое число.
При первом вызове f1()
, поскольку ожидаемым аргументом является an u8
, Rust выводит, что a
на самом деле это an u8
.
То же самое относится и к b
выведенному как i64
при первом использовании f2()
.
Конечно, если после этого мы попытаемся заставить компилятор вывести другие типы для этих переменных, это не удастся.
В вашем случае вы объявляете свои статические привязки как хэш-карты определенного типа: Token
в одном случае, AminoAcid
в другом. Затем фигурная скобка, используемая для инициализации такой привязки, должна соответствовать этому типу; соответственно выводится тип результирующего выражения ( m
) . Способ инициализации m
предполагает правильный тип значения. Следовательно, выбирается версия into()
предоставления этого типа.
Комментарии:
1. Это абсолютно вывод типа. Я должен также добавить, что это не всегда будет возможно, если окружающий код не предоставил механизму вывода типов достаточно информации, и в этом случае вы увидите ошибку компилятора с просьбой уточнить (либо путем добавления дополнительных подсказок типа, либо полного синтаксиса функции, который указывает, какую
Into
черту вы хотитедля использования)
Ответ №2:
Поскольку вы определили тип HASHMAP
, компилятор определяет, какой тип необходим, поскольку, если он преобразуется в другой тип, он не будет компилироваться. https://doc.rust-lang.org/rust-by-example/types/inference.html