1、&变量 => 不可变取地址
1. 传递内存地址
fn run(x: &i32){
println!("{}", x)
}
fn main()
{
let x = 5;
run(&x);
}
➜ main make
rustc main.rs
./main
5
➜ main
2. 传递数组
fn foo(s: &[i32]) {
println!("{:?}", s)
}
fn main()
{
// Vec<T> implements Deref<Target=[T]>
let owned = vec![1, 2, 3];
foo(&owned);
}
➜ main make
rustc main.rs
./main
[1, 2, 3]
➜ main
3. 无法通过地址修改内存数据
fn run(x: &i32){
x += 1; // error:
println!("{}", x)
}
fn main()
{
let mut x = 5;
run(&x);
}
➜ main make
rustc main.rs
error[E0368]: binary assignment operation `+=` cannot be applied to type `&i32`
--> main.rs:2:3
|
2 | x += 1; // error:
| -^^^^^
| |
| cannot use `+=` on type `&i32`
error: aborting due to previous error
make: *** [all] Error 101
➜ main
2、&mut 变量 => 可变取地址
1. 可通过内存地址修改内存中数据
fn main()
{
let mut x = 5; // mut可变绑定
println!("x = {}", x);
{
let ptr = &mut x; // &mut 获取可变类型的内存地址
*ptr += 1;
}
println!("x = {}", x);
}
➜ main make
rustc main.rs
./main
x = 5
x = 6
➜ main
2. 函数形参为内存地址
eg1
fn run(ptr: &mut i32)
{
*ptr += 1;
}
fn main()
{
let mut x = 5;
println!("x = {}", x);
// 先取&mut引用,再传递&mut引用给被调用函数
{
let ptr = &mut x;
run(ptr);
}
println!("x = {}", x);
}
➜ main make
rustc main.rs
./main
x = 5
x = 6
➜ main
eg2
fn run(ptr: &mut i32)
{
*ptr += 1;
}
fn main()
{
let mut x = 5;
println!("x = {}", x);
// 一步传地址
run(&mut x);
println!("x = {}", x);
}
➜ main make
rustc main.rs
./main
x = 5
x = 6
➜ main
3、引用不被释放的内存
1. 指向局部内存
fn main()
{
// 引用类型的变量
let y: &i32;
// 局部内存块
{
let x = 5; // 局部内存
y = &x; // 让外部的指针变量,指向局部内存块
}
// 通过指针访问已经被释放的内存块
println!("{}", y);
}
➜ main make
rustc main.rs
error[E0597]: `x` does not live long enough
--> main.rs:9:10
|
9 | y = &x; // 让外部的指针变量,指向局部内存块
| ^ borrowed value does not live long enough
10 | }
| - `x` dropped here while still borrowed
...
14 | }
| - borrowed value needs to live until here
error: aborting due to previous error
make: *** [all] Error 101
➜ main
对于 y = &x; 报错 => 使用了一个没有生命周期的内存
borrowed value does not live long enough
对于 x 报错 => x 已经被释放
`x` dropped here while still borrowed
换句话说,y 只在 X 存在的作用域内有效。一旦 x 消失了,它将会变成一个 x 的无效引用。因此,上面代码中的错误中说借用‘活的时间不够长’,因为它在有效的矢量的时间内是无效的。
2. 引用变量在实例变量定义之前声明
No
fn main()
{
// 先声明指针变量
let y: &i32;
// 再定义变量分配局部栈帧内存
let x = 5;
// 赋值指针变量指向栈帧上内存地址
y = &x;
}
➜ main make
rustc main.rs
error[E0597]: `x` does not live long enough
--> main.rs:10:8
|
10 | y = &x;
| ^ borrowed value does not live long enough
11 | }
| - `x` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
error: aborting due to previous error
make: *** [all] Error 101
➜ main
同样是报错
`x` does not live long enough
`x` dropped here while still borrowed
- 引用变量y先入栈,实例变量x后入栈,那么实例变量x处于栈顶
- 栈帧弹出时,先弹出栈顶的实例变量x的内存块,再弹出引用变量y的内存块
- 就会造成引用变量y会引用一个已经被释放的内存块
Yes
fn main()
{
// 再定义变量分配局部栈帧内存
let x = 5;
// 先声明指针变量
let y: &i32;
// 赋值指针变量指向栈帧上内存地址
y = &x;
}
➜ main make
rustc main.rs
./main
➜ main
4、所有权的转移与借用
1. 内存所有权
fn foo() {
let v = vec![1, 2, 3];
}
- 进入foo()时将新创建新的Vec对象,并在堆区分配三个内存单元存储1、2、3
- 由局部变量v绑定拥有Vec对象所在内存块
- 当局部变量v超出foo()作用域时,会被自动清理掉
- 那么Vec对象所在内存块也就失去了拥有者,所以也会被自动清理掉
2. 内存块所有权的转移
1. 【值赋值】方式会触发内存块所有权的转移
fn main()
{
let v1 = vec![1, 2, 3]; // v1先持有vec对象内存块
let v2 = v1; // v2也持有vec对象内存块,但是会自动解除v1对vec对象内存块的持有
println!("v1[0] is: {}", v1[0]); // 此时v1不能再使用vec对象内存块
}
➜ main make
rustc main.rs
error[E0382]: use of moved value: `v1`
--> main.rs:5:28
|
4 | let v2 = v1; // v2也持有vec对象内存块,但是会自动解除v1对vec对象内存块的持有
| -- value moved here
5 | println!("v1[0] is: {}", v1[0]); // 此时v1不能再使用vec对象内存块
| ^^ value used here after move
|
= note: move occurs because `v1` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
error: aborting due to previous error
make: *** [all] Error 101
➜ main
核心错误提示:use of moved value: v1
2. 【值传递】方式会触发内存块所有权的转移
fn take(v: Vec<i32>) {
// what happens here isn’t important.
}
fn main()
{
// mian()内变量v持有vec对象
let v = vec![1, 2, 3];
// 调用take(),使用【值传递】方式传递v持有的vec对象,
// => 会触发对vec对象所有权的转移
// => main()中的局部变量v此时会【解除】对vec对象的所有权
take(v);
// main()内的局部变量v无法再通过v读写vec对象的内存
println!("v[0] is: {}", v[0]);
}
➜ main make
rustc main.rs
error[E0382]: use of moved value: `v`
--> main.rs:16:27
|
13 | take(v);
| - value moved here
...
16 | println!("v[0] is: {}", v[0]);
| ^ value used here after move
|
= note: move occurs because `v` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
error: aborting due to previous error
make: *** [all] Error 101
➜ main
核心错误提示:use of moved value: v
3. Copy 拷贝取消默认的 Move控制权转移
1. 基本数据类型的Copy
fn main()
{
let a = 1;
let b = a; // 并非使用的【内存所有权转移】,而是执行【内存块数据的拷贝】
println!("a = {}", a); // 仍然可以使用变量a绑定的内存块
}
➜ main make
rustc main.rs
./main
a = 1
➜ main
正常执行。
2. 函数返回传入的vec对象来恢复所有权
fn foo(v: Vec<i32>) -> Vec<i32> {
// do stuff with v
v // 返回接收的vec对象,恢复被掉函数中变量的所有权
}
fn main()
{
let v1 = vec![1, 2, 3];
// => v1 失去所有权
// => v2 在foo()执行完毕后返回时,获得所有权
let v2 = foo(v1);
// println!("{:?}", v1); // error: use of moved value: `v1`
println!("{:?}", v2); // ok
}
➜ main make
rustc main.rs
./main
[1, 2, 3]
➜ main
3. 当vec对象入参很多时,变得很复杂
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
// do stuff with v1 and v2
// 返回 v1, v2 => 为了让主调函数中恢复对传入的两个vec对象的所有权
// 返回 42 => foo()运算结果值
(v1, v2, 42)
}
fn main()
{
let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];
// => 调用foo()时,v1、v2【失去】所有权
// => foo()返回时,v1、v2【恢复】所有权
let (v1, v2, answer) = foo(v1, v2);
println!("answer = {:?}", answer);
println!("v1 = {:?}", v1); // ok
println!("v2 = {:?}", v2); // ok
}
➜ main make
rustc main.rs
./main
answer = 42
v1 = [1, 2, 3]
v2 = [1, 2, 3]
➜ main
4. 接收与传递都使用 &T 【借用】使用权,避免因为move报错
eg1
fn foo(v: &Vec<i32>) {
// do stuff with v
}
fn main()
{
let v1 = vec![1, 2, 3];
// => 不用再通过函数返回至接收vec对象,来恢复对vec对象内存的所有权
// => 直接传递【&变量】给被调用函数
// => 【&变量】只是让被调用函数,【暂时借用】使用变量的内存块,并不涉及所有权转移
foo(&v1);
// foo()执行完毕后,仍然可以使用v1读写vec对象内存
println!("{:?}", v1); // ok
}
➜ main make
rustc main.rs
./main
[1, 2, 3]
➜ main
eg2
fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
42
}
fn main()
{
let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];
// 同上例
let answer = foo(&v1, &v2);
println!("answer = {:?}", answer);
println!("v1 = {:?}", v1); // ok
println!("v2 = {:?}", v2); // ok
}
➜ main make
rustc main.rs
./main
answer = 42
v1 = [1, 2, 3]
v2 = [1, 2, 3]
➜ main
5. &T 引用,无法再被调用函数中修改传入的内存
fn run(x: &i32){
x += 1; // error:
println!("{}", x)
}
fn main()
{
let mut x = 5;
run(&x);
}
➜ main make
rustc main.rs
error[E0368]: binary assignment operation `+=` cannot be applied to type `&i32`
--> main.rs:2:3
|
2 | x += 1; // error:
| -^^^^^
| |
| cannot use `+=` on type `&i32`
error: aborting due to previous error
make: *** [all] Error 101
➜ main
6. &mut T 引用,可以在被调用函数中修改传入的内存
fn run(x: &mut i32) {
*x += 1;
}
fn main()
{
let mut x = 5;
println!("x = {}", x);
run(&mut x);
println!("x = {}", x);
}
➜ main make
rustc main.rs
./main
x = 5
x = 6
➜ main
5、var、&var、&mut var 作用域问题
1. var、&var 能出现在一个作用域内
fn main()
{
// mut可变绑定
let mut x = 5;
println!("x = {}", x);
// &mut 获取可变类型的内存地址
let ptr = &x;
// error: cannot borrow `x` as immutable because it is also borrowed as mutable
println!("x = {}", x);
}
➜ main make
rustc main.rs
./main
x = 5
x = 5
➜ main
2. var、&mut var 不能出现在一个作用域内
fn main()
{
// mut可变绑定
let mut x = 5;
println!("x = {}", x);
// &mut 获取可变类型的内存地址
let ptr = &mut x;
// error: cannot borrow `x` as immutable because it is also borrowed as mutable
println!("x = {}", x);
}
➜ main make
rustc main.rs
warning: unused variable: `ptr`
--> main.rs:8:7
|
8 | let ptr = &mut x;
| ^^^
|
= note: #[warn(unused_variables)] on by default
= note: to avoid this warning, consider using `_ptr` instead
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> main.rs:11:22
|
8 | let ptr = &mut x;
| - mutable borrow occurs here
...
11 | println!("x = {}", x);
| ^ immutable borrow occurs here
12 | }
| - mutable borrow ends here
error: aborting due to previous error
make: *** [all] Error 101
➜ main
- 提示不能访问x
- 因为x已经被mutable
3. &var、&mut var 也不能同时出现在一个作用域
fn main()
{
// mut可变绑定
let mut x = 5;
println!("x = {}", x);
{
let ptr1 = &x; //&T
let ptr2 = &mut x; //&mut T
}
}
➜ main make
rustc main.rs
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
--> main.rs:9:21
|
8 | let ptr1 = &x;
| - immutable borrow occurs here
9 | let ptr2 = &mut x;
| ^ mutable borrow occurs here
10 | }
| - immutable borrow ends here
error: aborting due to previous error
make: *** [all] Error 101
➜ main
4. var、&var、&mut var 分作用域操作
fn main()
{
// var => 主作用域
let mut x = 5;
println!("x = {}", x);
// &var => 子用域1
{
let ptr1 = &x;
println!("ptr1 = {}", ptr1);
}
// &mut var => 子用域2
{
let ptr2 = &mut x;
*ptr2 += 1;
}
// var => 主作用域
println!("x = {}", x);
}
➜ main make
rustc main.rs
./main
x = 5
ptr1 = 5
x = 6
➜ main
5. 在for迭代时,不能对容器同时进行修改
fn main()
{
let mut v = vec![1, 2, 3];
for i in &v { // 读迭代器
println!("{}", i);
v.push(34); // 写迭代器
}
}
➜ main make
rustc main.rs
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> main.rs:7:5
|
5 | for i in &v { // 读迭代器
| - immutable borrow occurs here
6 | println!("{}", i);
7 | v.push(34); // 写迭代器
| ^ mutable borrow occurs here
8 | }
| - immutable borrow ends here
error: aborting due to previous error
make: *** [all] Error 101
➜ main
不能修改 V,因为它在循环中被借用。
网友评论