• 通用函数调用语法
    • 尖括号形式(Angle-bracket Form)

    通用函数调用语法

    ufcs.md


    commit ccb1d87d6faa9ff528d22b96595a0e2cbb16c0f2

    有时,函数可能有相同的名字。就像下面这些代码:

    1. trait Foo {
    2. fn f(&self);
    3. }
    4. trait Bar {
    5. fn f(&self);
    6. }
    7. struct Baz;
    8. impl Foo for Baz {
    9. fn f(&self) { println!("Baz’s impl of Foo"); }
    10. }
    11. impl Bar for Baz {
    12. fn f(&self) { println!("Baz’s impl of Bar"); }
    13. }
    14. let b = Baz;

    如果我们尝试调用b.f(),我们会得到一个错误:

    1. error: multiple applicable methods in scope [E0034]
    2. b.f();
    3. ^~~
    4. note: candidate #1 is defined in an impl of the trait `main::Foo` for the type
    5. `main::Baz`
    6. fn f(&self) { println!("Baz’s impl of Foo"); }
    7. ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    8. note: candidate #2 is defined in an impl of the trait `main::Bar` for the type
    9. `main::Baz`
    10. fn f(&self) { println!("Baz’s impl of Bar"); }
    11. ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    我们需要一个区分我们需要调用哪一函数的方法。这个功能叫做“通用函数调用语法”(universal function call syntax),这看起来像这样:

    1. # trait Foo {
    2. # fn f(&self);
    3. # }
    4. # trait Bar {
    5. # fn f(&self);
    6. # }
    7. # struct Baz;
    8. # impl Foo for Baz {
    9. # fn f(&self) { println!("Baz’s impl of Foo"); }
    10. # }
    11. # impl Bar for Baz {
    12. # fn f(&self) { println!("Baz’s impl of Bar"); }
    13. # }
    14. # let b = Baz;
    15. Foo::f(&b);
    16. Bar::f(&b);

    让我们拆开来看。

    1. Foo::
    2. Bar::

    调用的这一半是两个 trait 的类型:FooBar。这样实际上就区分了这两者:Rust 调用你使用的 trait 里面的方法。

    1. f(&b)

    当我们使用方法语法调用像b.f()这样的方法时,如果f()需要&self,Rust 实际上会自动地把b借用为&self。而在这个例子中,Rust 并不会这么做,所以我们需要显式地传递一个&b

    尖括号形式(Angle-bracket Form)

    我们刚才讨论的通用函数调用语法的形式:

    1. Trait::method(args);

    上面的形式其实是一种缩写。这是在一些情况下需要使用的扩展形式:

    1. <Type as Trait>::method(args);

    <>::语法是一个提供类型提示的方法。类型位于<>中。在这个例子中,类型是Type as Trait,表示我们想要methodTrait版本被调用。在没有二义时as Trait部分是可选的。尖括号也是一样。因此上面的形式就是一种缩写的形式。

    这是一个使用较长形式的例子。

    1. trait Foo {
    2. fn foo() -> i32;
    3. }
    4. struct Bar;
    5. impl Bar {
    6. fn foo() -> i32 {
    7. 20
    8. }
    9. }
    10. impl Foo for Bar {
    11. fn foo() -> i32 {
    12. 10
    13. }
    14. }
    15. fn main() {
    16. assert_eq!(10, <Bar as Foo>::foo());
    17. assert_eq!(20, Bar::foo());
    18. }

    使用尖括号语法让你可以调用指定 trait 的方法而不是继承到的那个。