gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 07:59:15 26 4
gpt4 key购买 nike

在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 })
}

最佳答案

摘要:最重要的区别是双向 f 联合 c 所有语法(UFCS)是,而不是更明确的语法。

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

  • 方法分辨率:确定该方法是固有的(绑定(bind)到类型,而不是特征)或特征方法。在后一种情况下,还要弄清楚它属于哪个特征。
  • 找出正确的接收者类型(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种组合。

    UFCS

    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 trait描述。允许您在数组上调用切片方法,并将类型强制转换为它们实现的特征的特征对象。
  • 通过the Deref trait 取消强制强制。例如,这允许您在Vec上调用slice方法。




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

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

    为了粗略地概述其工作方式,编译器将使用找到的第一种方法按顺序尝试以下操作。
  • 是否存在名称为method_name的固有方法,其中接收者类型恰好适合(不需要强制)?
  • 是否有名称为method_name的特征方法,接收方类型完全适合(不需要强制)?
  • 是否存在名称为method_name的固有方法? (将执行类型强制)
  • 是否存在名称为method_name的trait方法? (将执行类型强制)

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

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

    这组规则实际上可以对API进行大量更改以破坏更改。当前,我们必须处理那个in the attempt to add an IntoIterator impl for arrays



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

    除此之外,值得指出两种语法没有什么不同:
  • 运行时行为:没有任何区别。
  • 性能:基本上在编译器内部,方法调用语法就被“转换”(去掉了),基本上变成了UFCS,这意味着也没有任何性能差异。
  • 关于methods - 方法调用语法 `foo.method()`和UFCS `Foo::method(&foo)`有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58757127/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com