в rust-lang в чем разница между static_fly::<Number>(number);
и static_fly(number);
вот демо:
enum Number {
Zero,
One,
Two,
}
trait Fly {
fn fly(&self);
}
impl Fly for Number {
fn fly(&self) {
println!("flying number: {}", self)
}
}
// 静态分发
fn static_fly<T: Fly>(f: T){
print!("静态分发\t");
f.fly()
}
fn main() {
let number = Zero;
// 泛型的分发调用
static_fly(number); // <-- here is the 1st method for calling static_fly
// static_fly::<Number>(number); // <-- here is the 2nd method for calling static_fly
}
в чем разница между этими двумя вызовами.
я обновил демо
Два метода вызова функции в этом случае эквивалентны.
Имея достаточно информации, Rust может вывести аргументы универсального типа. В случае static_fly(number)
компилятор сделал вывод, что T
есть Number
. В случае static_fly::<Number>(number)
вы просто явно указываете тип аргумента типа T
.
Это очень похоже на другие виды вывода, которые выполняет компилятор. Например, оба эти утверждения также эквивалентны:
let number = Zero;
let number: Number = Zero;
Принцип тот же — в одном случае мы указываем тип, а в другом позволяем компилятору разобраться.
Это то же самое, что let a = b;
по сравнению с let a: Type = b;
. Это дает вам возможность явно указать, какой тип используется в операции. Обычно Rust может сделать вывод о том, что вы хотите сделать, однако, если есть какая-либо двусмысленность, компилятор попросит вас явно указать тип.
Например, чаще всего я сталкиваюсь с этим при вызове .collect()
на итераторе.
fn foo(vals: &[u32]) -> Vec<u32> {
// In this case there is no ambiguity since the result of collect must
// be a `Vec<u32>`. Since the compiler can infer the type, we don't need
// to state what type collect uses.
vals.iter()
.map(|x| x * 2)
.collect()
}
fn bar(vals: &[u32]) -> u32 {
// In this case the compiler is unable to infer a type as collect can
// create any type that can be initialized with an iterator.
let mut a = vals.iter()
.map(|x| x * 2)
.collect();
a.sort();
a[0]
}
Для этого примера есть несколько способов исправить bar
.
// State the type of a so the compiler can infer collect's types
let mut a: Vec<u32> = vals.iter()
.map(|x| x * 2)
.collect();
// State the types used by the function in question but let the compiler infer a's type
let mut a = vals.iter()
.map(|x| x * 2)
.collect::<Vec<u32>>();
Другой вариант — указать тип, о котором идет речь, лишь частично. Имя типа можно заменить символом подчеркивания, чтобы компилятор понял, что нужно вывести эту часть типа. Как правило, это мой предпочтительный способ обработки этого конкретного случая.
// Tell the compiler we will collect items to a Vec, but let it infer the content type
let mut a = vals.iter()
.map(|x| x * 2)
.collect::<Vec<_>>();
Где заявлено
number
?