Иногда, функции могут иметь одинаковые имена. Рассмотрим этот код:
fn main() { trait Foo { fn f(&self); } trait Bar { fn f(&self); } struct Baz; impl Foo for Baz { fn f(&self) { println!("Baz’s impl of Foo"); } } impl Bar for Baz { fn f(&self) { println!("Baz’s impl of Bar"); } } let b = Baz; }trait Foo { fn f(&self); } trait Bar { fn f(&self); } struct Baz; impl Foo for Baz { fn f(&self) { println!("Baz’s impl of Foo"); } } impl Bar for Baz { fn f(&self) { println!("Baz’s impl of Bar"); } } let b = Baz;
Если мы попытаемся вызвать b.f()
, то получим ошибку:
error: multiple applicable methods in scope [E0034]
b.f();
^~~
note: candidate #1 is defined in an impl of the trait `main::Foo` for the type
`main::Baz`
fn f(&self) { println!("Baz’s impl of Foo"); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: candidate #2 is defined in an impl of the trait `main::Bar` for the type
`main::Baz`
fn f(&self) { println!("Baz’s impl of Bar"); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Нам нужен способ указать, какой конкретно метод нужен, чтобы устранить неоднозначность. Эта возможность называется «универсальный синтаксис вызова функций», и выглядит это так:
fn main() { trait Foo { fn f(&self); } trait Bar { fn f(&self); } struct Baz; impl Foo for Baz { fn f(&self) { println!("Baz’s impl of Foo"); } } impl Bar for Baz { fn f(&self) { println!("Baz’s impl of Bar"); } } let b = Baz; Foo::f(&b); Bar::f(&b); }Foo::f(&b); Bar::f(&b);
Давайте разберемся.
fn main() { Foo:: Bar:: }Foo:: Bar::
Эти части вызова задают один из двух видов типажей: Foo
и Bar
. Это то, что
на самом деле устраняет неоднозначность между двумя методами: Rust вызывает
метод того типажа, имя которого вы используете.
f(&b)
Когда мы вызываем метод, используя синтаксис вызова метода, как
например b.f()
, Rust автоматически заимствует b
, если f()
принимает в
качестве аргумента &self
. В этом же случае, Rust не будет использовать
автоматическое заимствование, и поэтому мы должны явно передать &b
.
Форма UFCS, о которой мы только что говорили:
fn main() { Trait::method(args); }Trait::method(args);
Это сокращенная форма записи. Ниже представлена расширенная форма записи, которая требуется в некоторых ситуациях:
fn main() { <Type as Trait>::method(args); }<Type as Trait>::method(args);
Синтаксис <>::
является средством предоставления подсказки типа. Тип
располагается внутри <>
. В этом случае типом является Type as Trait
,
указывающий, что мы хотим здесь вызвать Trait
версию метода. Часть as Trait
является необязательной, если вызов не является неоднозначным. То же самое что с
угловыми скобками, отсюда и короткая форма.
Вот пример использования длинной формы записи.
fn main() { trait Foo { fn clone(&self); } #[derive(Clone)] struct Bar; impl Foo for Bar { fn clone(&self) { println!("Making a clone of Bar"); <Bar as Clone>::clone(self); } } }trait Foo { fn clone(&self); } #[derive(Clone)] struct Bar; impl Foo for Bar { fn clone(&self) { println!("Making a clone of Bar"); <Bar as Clone>::clone(self); } }
Этот код вызывает метод clone()
типажа Clone
, а не типажа Foo
.