use std::ops::Add;
#[derive(Debug)]
struct Sample {
pub value: usize,
}
impl std::ops::Add<&Sample> for &Sample {
type Output = Sample;
fn add(self, other: &Sample) -> Sample {
Sample {
value: self.value + other.value,
}
}
}
fn main() {
let mut a = Sample { value: 0 };
let b = Sample { value: 1 };
let mut_a = &mut a;
let immut_b = &b;
println!("Works: {:?}", mut_a.add(immut_b));
println!("And this works: {:?}", immut_b.add(mut_a));
println!("Also works:: {:?}", immut_b + mut_a);
println!("Still works:: {:?}", &*mut_a + immut_b);
println!("Fails: {:?}", mut_a + immut_b);
}
Run Code Online (Sandbox Code Playgroud)
在此代码中add需要两个&Samples。在 main 方法中,我创建了对两个不同Samples 的两个引用,一个是可变的,一个是不可变的。我可以按add任一顺序显式调用它们,但如果我使用+运算符,它会抱怨可变引用首先出现。(将其重新借用为不可变也可以使其工作。)我希望可变引用在不可变引用所在的任何地方都有效。是什么赋予了?
为了加深神秘感,我尝试对基本的 s 做同样的事情i32-
let mut x: i32 = 0;
let y: i32 = 1;
let mut_x = &mut x;
let immut_y = &y;
println!("But this doesn't work? {:?}", immut_y + mut_x);
println!("Or this? {:?}", mut_x + immut_y);
println!("And this does? {:?}", mut_x.add(immut_y));
println!("But not this? {:?}", immut_y.add(mut_x));S
Run Code Online (Sandbox Code Playgroud)
并得到了完全不同的意外行为 - 现在我无法使用+运算符以任何顺序添加它们,并且只有在可变对象上调用该函数时,显式调用才有效。
对于第一个片段,情况是,虽然方法调用是通过自动解引用解决的,但重载运算符却不是。
println!("Works: {:?}", mut_a.add(immut_b));
Run Code Online (Sandbox Code Playgroud)
通过自动解引用,我们能够将&mut Sample参数传递到&Sample预期的位置。为了决定调用哪个方法,rust 大致做了:
[&mut Sample, &&mut Sample, &mut &mut Sample, Sample, &Sample, &mut Sample]。add,其接收的类型&Sample与self类型完全相同。找到该点后&Sample,rust 会自动取消引用/引用mut_a以使调用正常工作。所以脱糖后的代码如下所示:<&Sample>::add(&*mut_a, immut_b);
Run Code Online (Sandbox Code Playgroud)
仅此一点并不能解释有关自动取消引用的更多信息,您应该检查上面的链接。
println!("And this works: {:?}", immut_b.add(mut_a));
Run Code Online (Sandbox Code Playgroud)
自动取消引用会在第一步解析方法,而无需任何自动取消引用/引用。
println!("Also works:: {:?}", immut_b + mut_a);
Run Code Online (Sandbox Code Playgroud)
由于这不是方法调用表达式,因此根本不存在自动取消引用。Add推断特征的实现类型。相当于:
::std::ops::Add::add(immut_b, mut_a);
Run Code Online (Sandbox Code Playgroud)
println!("Still works:: {:?}", &*mut_a + immut_b);
Run Code Online (Sandbox Code Playgroud)
与上面相同,只是没有对右操作数进行强制。
println!("Fails: {:?}", mut_a + immut_b);
Run Code Online (Sandbox Code Playgroud)
Rust 无法推断特征的实现类型,因为它只查找不存在的Addfor的实现。&mut Sample与方法调用表达式不同,在这种情况下没有自动取消引用,并且 rust 不会做任何进一步的事情来解决。粗略脱糖的代码(也因同样的原因失败):
<&mut Sample as ::std::ops::Add<&Sample>>::add(mut_a, immut_b);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
250 次 |
| 最近记录: |