let x = 5;
let y = &5;
let z= &x;
x 是 i32 整型,y,z 是引用类型,用 & 是取引用符
新加变量 x, 并绑定 5 数据,
新增加变量 y,并绑定 5 数据的引用地址
新增变量 z, 并绑定 x 的引用地址
上面每个变量在内存中都是不同的存储
第一行,在栈中添加变量,而且变量的值是 5,都在栈中
第二行,在栈中增加一个数据 5,再再栈中创建一个变量 y,并把 5 所在的内存地址,给 y;
第三行 在栈中增加一个变量,把 x 所在的内存地址赋值给 z
每行都是在内存新开辟一块空间,存变量,而且变量的值都是不同的,y 和 z 的内存地址并不相同
let x = 5;
let h = &x;
let k = &x;
上面 h,k 拥有相同的值,x 的内存地址确定,h,k 都是取 x 的内存地址,所有 h 和 k 是同等的,根据之前的说明,那如果
let g = &5; 是不是就说明 h==k 是 true, h==g 是 false,k==g 也是 false
其实不然,虽然 g=&5; g 的值和 h,k 都不相同,但是在调用 == 的时候,会产生自动解码的操作,会直接比较指针的值所以,h==g 和 k==g 都是 true
有点需要特别说明,指针的指针这种情况,看下面例子, 先不提有没有必要,编译器是支持的
let x = 5;
let y = &&x;
let z = &&x;
y 和 z 的内存地址是不相同的,具体的原理不是很明白,就根据我的理解(我让我信服的理由)&x 取 x 的引用保存到一块空间,&&x 然后再取这个空间的地址,因为我们并没有把 &x; 存这块空间绑定到一个变量上,所以每次取 &x, 都会产生一个新的空间,所以每次取这个地址都是一个新的内存地址。
最后说下解引用,就是用 * 号来解引用,使用引用指向的数据,如果没有解引用,那就是
let x = 5;
let y = &5;
let z = x+*y;
上面代码没有错,正常编译执行,y 的类型是个 引用类型,* 号把 y 解引用就是 5,相加正常,
如果 z 换成 let z = x+y; 呢,也是正常执行和编译的,这是因为编译器自动把 y 解引用了,
impl<'a,'b> Add<&'a i32> for &'b i32
fn add(self, other: &'a i32) -> >::Output
类似于如何使用 Deref trait 重载不可变引用的 * 运算符,Rust 提供了 DerefMut trait 用于重载可变引用的 * 运算符。
Rust 在发现类型和 trait 实现满足三种情况时会进行解引用强制多态:
当 T: Deref 时从 &T 到 &U。
当 T: DerefMut 时从 &mut T 到 &mut U。
当 T: Deref 时从 &mut T 到 &U。
头两个情况除了可变性之外是相同的:第一种情况表明如果有一个 &T,而 T 实现了返回 U 类型的 Deref,则可以直接得到 &U。第二种情况表明对于可变引用也有着相同的行为。
最后一个情况有些微妙:Rust 也会将可变引用强转为不可变引用。但是反之是 不可能 的:不可变引用永远也不能强转为可变引用。因为根据借用规则,如果有一个可变引用,其必须是这些数据的唯一引用(否则程序将无法编译)。将一个可变引用转换为不可变引用永远也不会打破借用规则。将不可变引用转换为可变引用则需要数据只能有一个不可变引用,而借用规则无法保证这一点。因此,Rust 无法假设将不可变引用转换为可变引用是可能的
作者:zqliang
链接:https://hacpai.com/article/1540173433079
来源:黑客派
协议:CC BY-SA 4.0 https://creativecommons.org/licenses/by-sa/4.0/