let x = 5;指针
let y = &5;内存
let z= &x;编译器
x 是 i32 整型,y,z 是引用类型,用 & 是取引用符it
新加变量 x, 并绑定 5 数据,编译
新增长变量 y,并绑定 5 数据的引用地址变量
新增变量 z, 并绑定 x 的引用地址原理
上面每一个变量在内存中都是不一样的存储引用
第一行,在栈中添加变量,并且变量的值是 5,都在栈中程序
第二行,在栈中增长一个数据 5,再再栈中建立一个变量 y,并把 5 所在的内存地址,给 y;im
第三行 在栈中增长一个变量,把 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/