方法调用语法`foo.method()`和UFCS`Foo :: method(&foo)`有什么区别?

乔尔

在Rust上对值调用方法之间是否有任何区别,如下所示:

struct A { e: u32 }

impl A {
    fn show(&self) {
        println!("{}", self.e)
    }
}

fn main() {
    A { e: 0 }.show();
}

...并按类型调用它,如下所示:

fn main() {
    A::show(&A { e: 0 })
}
卢卡斯(Lukas Kalbertodt)

摘要:最重要的区别是,ü niversal ˚FÇ所有小号yntax(UFCS)是更加明确方法调用语法

有了UFCS,基本上就没有什么要调用的函数的歧义了(对于trait方法,UFCS的形式仍然更长一些,但是现在让我们忽略它)。另一方面,方法调用语法需要在编译器中进行更多工作才能确定要调用的方法以及如何调用它。这主要表现为两件事:

  • 方法解析:找出方法是固有的(绑定到类型,而不是特征)还是特征方法。在后一种情况下,还要弄清楚它属于哪个特征。
  • 找出正确的接收者类型(self),并可能使用类型强制来使呼叫正常进行。



接收器类型的强制

让我们看一下这个示例,以了解对接收器类型的强制类型:

struct Foo;

impl Foo {
    fn on_ref(&self) {}
    fn on_mut_ref(&mut self) {}
    fn on_value(self) {}
}

fn main() {
    let reference = &Foo;    // type `&Foo`
    let mut_ref = &mut Foo;  // type `&mut Foo`
    let mut value = Foo;     // type `Foo`

    // ... 
}

因此,我们有三种方法采取Foo&Foo以及&mut Foo接收器,我们必须对这些类型的三个变量。让我们尝试使用方法调用语法和UFCS的所有9种组合。

超滤系统

Foo::on_ref(reference);    
//Foo::on_mut_ref(reference);  error: mismatched types
//Foo::on_value(reference);    error: mismatched types

//Foo::on_ref(mut_ref);      error: mismatched types
Foo::on_mut_ref(mut_ref);  
//Foo::on_value(mut_ref);    error: mismatched types

//Foo::on_ref(value);      error: mismatched types
//Foo::on_mut_ref(value);  error: mismatched types
Foo::on_value(value);

如我们所见,只有类型正确的调用才能成功。为了使其他调用正常工作,我们必须在参数前手动添加&&mut*这是所有函数参数的标准行为。

方法调用语法

reference.on_ref();
//reference.on_mut_ref();  error: cannot borrow `*reference` as mutable
//reference.on_value();    error: cannot move out of `*reference`

mut_ref.on_ref();
mut_ref.on_mut_ref();
//mut_ref.on_value();      error: cannot move out of `*mut_ref`

value.on_ref();
value.on_mut_ref();
value.on_value();

该方法调用中只有三个导致错误,而其他方法成功。在这里,编译器会自动插入deref(解引用)或autoref(添加引用)强制,以使调用正常进行。另请注意,这三个错误不是“类型不匹配”错误:编译器已尝试正确调整类型,但这会导致其他错误。


还有一些其他强制措施:

  • Unsize的强制,由所描述的Unsize特征允许您在数组上调用切片方法,并将类型强制转换为它们实现的特征的特征对象。
  • 高级通过强制转换DEREFDeref特质例如,这使您可以在上调用slice方法Vec



方法解析:找出要调用的方法

在编写时lhs.method_name(),该方法method_name可以是类型的固有方法,lhs也可以属于范围(导入)的特征。编译器必须弄清楚要调用哪一个,并且为此有许多规则。当进入细节时,这些规则实际上确实很复杂,并且可能导致某些令人惊讶的行为。幸运的是,大多数程序员永远都不必处理这个问题,并且它在大多数情况下“有效”。

为了大致概述其工作方式,编译器使用找到的第一种方法按顺序尝试以下操作。

  • 是否有名称固有的方法,method_name其中接收方的类型恰好适合该类型(不需要强制)?
  • 是否有一个特征方法,其名称method_name恰好适合接收者类型(不需要强制)?
  • 是否有名称固有的方法method_name(将执行类型强制)
  • 有名称的特征方法method_name吗?(将执行类型强制)

(再次,请注意,这仍然是一种简化。例如,不同类型的强制比其他类型的强制更可取。)

这显示了大多数程序员都知道的一个规则:固有方法比特质方法具有更高的优先级。但是,一个更重要的因素是,接收器类型是否完全适合这一事实,这是一个未知数。有一个很好地证明了这一点的测验:Rust测验#23有关精确方法解析算法的更多详细信息,请参见此StackOverflow答案

这组规则实际上可以对API进行大量更改以破坏更改。当前,我们不得不处理该问题,以尝试IntoIterator为array添加一个impl




另一个(可能非常明显)的区别是,对于方法调用语法,不必导入类型名称。

除此之外,值得指出两种语法没有什么不同

  • 运行时行为:没有任何区别。
  • 性能:方法调用语法在编译器内部很早就被“转换”为(基本上已分解)为UFCS,这意味着也没有任何性能差异。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

&foo :: function和foo :: function有什么区别?

来自分类Dev

Bash中的`declare foo`和`foo =`有什么区别?

来自分类Dev

ifeq($ {foo),)和ifndef foo有什么区别

来自分类Dev

$ foo === TRUE和TRUE === $ foo有什么区别

来自分类Dev

my $ foo和my($ foo)有什么区别?

来自分类Dev

ifeq($(foo),)和ifndef foo有什么区别

来自分类Dev

使用params [:foo]和@foo有什么区别?

来自分类Dev

Bash 中的 `declare foo` 和 `foo=` 有什么区别?

来自分类Dev

python中装饰器中的foo=bar(foo)和something=bar(foo)有什么区别?

来自分类Dev

`this instanceof String`和`“ foo” instanceof String`有什么区别?

来自分类Dev

TypeScript中的类型化数组-Array <Foo>和Foo []有什么区别?

来自分类Dev

foo(int arr [])和foo(int arr [10])有什么区别?

来自分类Dev

当sub Foo :: bar {}和sub bar {}都属于包Foo时,有什么区别?

来自分类Dev

foo.toString()和Object.prototype.toString.call(foo)有什么区别?

来自分类Dev

Boolean(foo.bar)和!! foo.bar有什么区别?

来自分类Dev

TypeScript中的类型化数组-Array <Foo>和Foo []有什么区别?

来自分类Dev

直接使用shell命令(例如foo)和使用$(foo)有什么区别?

来自分类Dev

Scala中的s“ foo $ bar”和“ foo%s” .format(bar)有什么区别

来自分类Dev

如果有什么区别![[ foo ]] 并且如果 [[ ! foo ]] 在 Bash 中?

来自分类Dev

“使用名称空间栏”和“使用Bar :: Foo”之间有什么区别?

来自分类Dev

<%= foo%>和$ {foo}之间的区别

来自分类Dev

<%= foo%>和$ {foo}之间的区别

来自分类Dev

为什么resolve(“。/ .. / ....”)和resolve(“ foo”)之间有区别

来自分类Dev

object.method();有什么区别?vs方法(对象);?

来自分类Dev

PHP:{$ foo}和$ {foo}之间有区别吗

来自分类Dev

(?=。* foo \ b)和(?=。* foo)\ b之间的区别

来自分类Dev

“ function foo(){}”和“ foo(){}”之间的区别

来自分类Dev

@ foo,self.foo和foo之间的区别?

来自分类Dev

使用 method.invoke 和只在 java 中运行公共方法的方法有什么区别?

Related 相关文章

  1. 1

    &foo :: function和foo :: function有什么区别?

  2. 2

    Bash中的`declare foo`和`foo =`有什么区别?

  3. 3

    ifeq($ {foo),)和ifndef foo有什么区别

  4. 4

    $ foo === TRUE和TRUE === $ foo有什么区别

  5. 5

    my $ foo和my($ foo)有什么区别?

  6. 6

    ifeq($(foo),)和ifndef foo有什么区别

  7. 7

    使用params [:foo]和@foo有什么区别?

  8. 8

    Bash 中的 `declare foo` 和 `foo=` 有什么区别?

  9. 9

    python中装饰器中的foo=bar(foo)和something=bar(foo)有什么区别?

  10. 10

    `this instanceof String`和`“ foo” instanceof String`有什么区别?

  11. 11

    TypeScript中的类型化数组-Array <Foo>和Foo []有什么区别?

  12. 12

    foo(int arr [])和foo(int arr [10])有什么区别?

  13. 13

    当sub Foo :: bar {}和sub bar {}都属于包Foo时,有什么区别?

  14. 14

    foo.toString()和Object.prototype.toString.call(foo)有什么区别?

  15. 15

    Boolean(foo.bar)和!! foo.bar有什么区别?

  16. 16

    TypeScript中的类型化数组-Array <Foo>和Foo []有什么区别?

  17. 17

    直接使用shell命令(例如foo)和使用$(foo)有什么区别?

  18. 18

    Scala中的s“ foo $ bar”和“ foo%s” .format(bar)有什么区别

  19. 19

    如果有什么区别![[ foo ]] 并且如果 [[ ! foo ]] 在 Bash 中?

  20. 20

    “使用名称空间栏”和“使用Bar :: Foo”之间有什么区别?

  21. 21

    <%= foo%>和$ {foo}之间的区别

  22. 22

    <%= foo%>和$ {foo}之间的区别

  23. 23

    为什么resolve(“。/ .. / ....”)和resolve(“ foo”)之间有区别

  24. 24

    object.method();有什么区别?vs方法(对象);?

  25. 25

    PHP:{$ foo}和$ {foo}之间有区别吗

  26. 26

    (?=。* foo \ b)和(?=。* foo)\ b之间的区别

  27. 27

    “ function foo(){}”和“ foo(){}”之间的区别

  28. 28

    @ foo,self.foo和foo之间的区别?

  29. 29

    使用 method.invoke 和只在 java 中运行公共方法的方法有什么区别?

热门标签

归档