Methods 方法调用语法`foo.method()`和UFCS`foo::method(&;foo)``之间有什么区别?
对值调用方法之间是否有任何区别,如下所示: 结构A{e:u32} 暗示{ fn show(&self){ println!(“{}”,self.e) } } fn main(){ A{e:0}.show(); } …并在类型上调用它,如下所示: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方法,还有一
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进行一系列更改,使其成为破坏性更改。我们现在必须处理这个问题
另一个微小的、可能非常明显的区别是,对于方法调用语法,不必导入类型名
除此之外,值得指出的是,这两种语法没有什么不同之处:
- 运行时行为:没有任何区别