В rust-lang, в чем разница между `static_fly::<Number>(число);` и `static_fly(число);`

в 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
}

в чем разница между этими двумя вызовами.

Где заявлено number?

cdhowie 19.03.2022 14:48

я обновил демо

duguying 19.03.2022 14:50
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
2
31
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Два метода вызова функции в этом случае эквивалентны.

Имея достаточно информации, 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<_>>();

Другие вопросы по теме

Как создать список имен классов и перебрать в нем статический метод?
Создавать словарь только один раз и использовать его при вызове словаря?
Можно ли инициализировать статические поля внутри статической функции?
Почему мы должны объявлять метод статическим для рекурсивного вызова в Java?
Как инициализировать статический массив определенным значением в функции на С++?
Ошибка ссылки переопределения С++, когда не используются «встроенные» или «статические» ключевые слова с бесклассовыми функциями
Почему рекомендуется использовать статические методы в Effective Java?
Объединенный путь находится за пределами компонента базового пути
Почему эти статические функции не возвращаются из другого потока, как ожидалось?
Уникальные статические переменные дочернего класса: объявленные родителем, инициализированные дочерними элементами и автоматически клонированные статические методы