在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 })
}
摘要:最重要的区别是,ü 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
特征。允许您在数组上调用切片方法,并将类型强制转换为它们实现的特征的特征对象。Deref
特质。例如,这使您可以在上调用slice方法Vec
。
在编写时lhs.method_name()
,该方法method_name
可以是类型的固有方法,lhs
也可以属于范围(导入)的特征。编译器必须弄清楚要调用哪一个,并且为此有许多规则。当进入细节时,这些规则实际上确实很复杂,并且可能导致某些令人惊讶的行为。幸运的是,大多数程序员永远都不必处理这个问题,并且它在大多数情况下“有效”。
为了大致概述其工作方式,编译器使用找到的第一种方法按顺序尝试以下操作。
method_name
其中接收方的类型恰好适合该类型(不需要强制)?method_name
恰好适合接收者类型(不需要强制)?method_name
?(将执行类型强制)method_name
吗?(将执行类型强制)(再次,请注意,这仍然是一种简化。例如,不同类型的强制比其他类型的强制更可取。)
这显示了大多数程序员都知道的一个规则:固有方法比特质方法具有更高的优先级。但是,一个更重要的因素是,接收器类型是否完全适合这一事实,这是一个未知数。有一个很好地证明了这一点的测验:Rust测验#23。有关精确方法解析算法的更多详细信息,请参见此StackOverflow答案。
这组规则实际上可以对API进行大量更改以破坏更改。当前,我们不得不处理该问题,以尝试IntoIterator
为array添加一个impl。
另一个(可能非常明显)的区别是,对于方法调用语法,不必导入类型名称。
除此之外,值得指出两种语法没有什么不同:
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句