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

Methods 方法调用语法`foo.method()`和UFCS`foo::method(&;foo)``之间有什么区别?,methods,rust,Methods,Rust,对值调用方法之间是否有任何区别,如下所示: 结构A{e:u32} 暗示{ fn show(&self){ println!(“{}”,self.e) } } fn main(){ A{e:0}.show(); } …并在类型上调用它,如下所示: fn main(){ A::show(&A{e:0}) } 摘要:最重要的区别在于universalffunctioncallsyntax(UFCS)比方法调用语法更加明确 对于UFC,基本上不存在您想要调用什么函数的模糊性(对于trait方法,还有一

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

结构A{e:u32} 暗示{ fn show(&self){ println!(“{}”,self.e) } } fn main(){ A{e:0}.show(); } …并在类型上调用它,如下所示:

fn main(){
A::show(&A{e:0})
}

摘要:最重要的区别在于universalffunctioncallsyntax(UFCS)比方法调用语法更加明确

对于UFC,基本上不存在您想要调用什么函数的模糊性(对于trait方法,还有一种更长形式的UFC,但现在让我们忽略它)。另一方面,方法调用语法需要编译器进行更多的工作,以确定要调用哪个方法以及如何调用它。这主要体现在两个方面:

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


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

structfoo;
impl-Foo{
fn on_ref(&self){}
fn on_mut_ref(&mut self){}
fn关于_值(自){
}
fn main(){
let reference=&Foo;//类型`&Foo`
让mut_ref=&mut Foo;//键入`&mut Foo`
让mut value=Foo;//键入`Foo`
// ... 
}
所以我们有三种方法,分别是
Foo
&Foo
&mut-Foo
接收器,我们有三种类型的变量。让我们用每个方法、调用语法和UFC来尝试所有9种组合

UFCS

Foo::on_ref(参考);
//Foo::on_mut_ref(参考);错误:类型不匹配
//Foo::on_值(参考);错误:类型不匹配
//Foo::on_ref(mut_ref);错误:类型不匹配
Foo::on_mut_ref(mut_ref);
//Foo::on_值(mut_ref);错误:类型不匹配
//Foo::on_ref(值);错误:类型不匹配
//Foo::on_mut_ref(值);错误:类型不匹配
Foo::on_值(value);
正如我们所看到的,只有类型正确的调用才会成功。要使其他调用正常工作,我们必须在参数前面手动添加
&
&mut
*
。这是所有函数参数的标准行为

方法调用语法

reference.on_ref();
//reference.on_mut_ref();错误:无法将“*reference”作为可变项借用
//参考。关于_值();错误:无法移出“*引用”`
mut_ref.on_ref();
mut_ref.on_mut_ref();
//mut_ref.on_value();错误:无法移出“*mut\u ref”`
值。在_ref()上;
在_mut_ref()上的值;
value.on_value();
只有三个方法调用导致错误,而其他方法调用成功。在这里,编译器自动插入deref(取消引用)或autoref(添加引用)强制以使调用工作。还请注意,这三个错误不是“类型不匹配”错误:编译器已经尝试正确调整类型,但这会导致其他错误


还有一些额外的强制措施:

  • 取消大小强制,由描述。允许您在数组上调用slice方法,并将类型强制转换为它们实现的trait的trait对象
  • 高级通过解除强制。例如,这允许您在
    Vec
    上调用切片方法


方法解析:确定要调用的方法 编写
lhs.method\u name()
时,方法
method\u name
可能是
lhs
类型的固有方法,也可能属于范围内的特征(导入)。编译器必须弄清楚要调用哪一个,并为此制定许多规则。当深入细节时,这些规则实际上非常复杂,可能会导致一些令人惊讶的行为。幸运的是,大多数程序员将永远不必处理这个问题,而且它在大多数情况下都“正常工作”

为了粗略地概述它是如何工作的,编译器使用找到的第一个方法按顺序尝试以下内容

  • 是否存在一个名为
    method\u name
    的固有方法,其中接收方类型正好适合(不需要强制)
  • 是否有一个名为
    method\u name
    的trait方法,其中接收方类型正好适合(不需要强制)
  • 是否存在名为
    方法\u name
    的固有方法?(将执行类型强制)
  • 是否有名为
    method\u name
    的trait方法?(将执行类型强制)
(请再次注意,这仍然是一种简化。例如,与其他类型的强制相比,不同类型的强制更为可取。)

这显示了大多数程序员都知道的一条规则:固有方法比特征方法具有更高的优先级。但有点未知的是,接收器类型是否完美匹配是一个更重要的因素。有一个测验很好地证明了这一点:。有关精确方法解析算法的更多详细信息,请参阅

这组规则实际上可以对一个API进行一系列更改,使其成为破坏性更改。我们现在必须处理这个问题




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

除此之外,值得指出的是,这两种语法没有什么不同之处:

  • 运行时行为:没有任何区别