开始学习Rust的指针,在Rust中也叫借用(引用),下文是一个意思。从最简单的类型开始。所有权概念什么的,就不再这里赘述了。本系列仅为自学笔记系列,错误之处难免,若引起误会请谅解。
一、不可变引用
Rust中对于简单类型,如int家族,默认是进行值拷贝的,所以一般不会探讨这类指针,实际给我们带来困惑的也不是这类指针。但为了深入理解其机制,我们还是从最简单的类型开始。
fn main() {
let a = 5;
let b = &a;
println!("{:?}", a);
println!("{:?}", b);
}
在这里,b为a的引用,实际上就是变量a的地址,其类型 为 “&i32”,与a的类型 i32是不同的。两行的输出都为 5;实际上最后一行对b进行了 隐式解引用(符号为*)操作。最后一行:
println!("{:?}", b);
实际上等于下面一行:
println!("{:?}", *b);
输出一样。
二、可变引用
对一个变量进行可变引用有一个约束前提,即该变量必须是可变的。如下代码会报错:
let a = 5;
let b = &mut a;
报错信息如下:“cannot borrow `a` as mutable, as it is not declared as mutable”。在a前面加上 mut 即可。
根据Rust的借用规则,一个变量同时只能有一个可变引用。根据实际测试发现,当a被b可变引用后,在b使用结束之前,a不可用。下面代码不可编译通过:
fn main() {
let mut a = 5;
let b = &mut a;
println!("{:?}", a);
println!("{:?}", b);
}
提示错误:“cannot borrow `a` as immutable because it is also borrowed as mutable”,调换最后两行 println! 的顺序即可。这里a即使拥有自己的所有权,但因为被借用走了,也不能再在b之前被使用了。同样,下面的代码也报类似的错误:
fn main() {
let mut a = 5;
let b = &a;
a = 10;
println!("{:?}", b);
println!("{:?}", a);
}
提示:“cannot assign to `a` because it is borrowed”。这样设计的目的避免了脏数据,程序在使用b的时候(作为a的借用),a却变了,这很容易引起bug。
既然a被借用走(不管是可变借用还是不可变借用)以后,在b结束生命之前不可用,那么如何改变a的值呢?参考下面代码:
fn main() {
let mut a = 5;
let b = &mut a;
*b += 10;
println!("{:?}", b);
println!("{:?}", a);
}
输出结果都为 15.
上述代码,b为a的可变引用,类型为&mut i32,与不可变引用是不同的类型。*b 你可以理解为就是a,对*b的计算赋值同样会改变b和a的值。
上述代码中: *b += 10 ,如果改为: b += 10; 则会得到如下提示错误:
“binary assignment operation `+=` cannot be applied to type `&mut {integer}`
help: `+=` can be used on `{integer}`, you can dereference `b`: `*`rustc(E0368)”
这其实和C语言的指针操作思路类似,但通过更严格的约束,避免了数据竞争和数据污染,保证了程序的正确性。