Drop 什么时候运行、按什么顺序运行,是写资源管理代码(锁、文件、连接)的基础。这篇给一个会打印自己名字的类型,把每种情形的 drop 顺序都真实跑出来,包括最容易误会的 `let _ =` 和 process::exit。
源码:
1 | struct D(&'static str);
2 | impl Drop for D { fn drop(&mut self) { println!(" drop {}", self.0); } }
3 | struct Pair { first: D, second: D }
4 | fn main() {
5 | println!("-- 局部变量");
6 | { let _a = D("a"); let _b = D("b"); let _c = D("c"); }
7 | println!("-- 结构体字段");
8 | { let _p = Pair { first: D("p.first"), second: D("p.second") }; }
9 | println!("-- Vec 元素");
10 | { let _v = vec![D("v0"), D("v1"), D("v2")]; }
11 | println!("-- 临时值在语句结束时 drop");
12 | { let _ = D("临时"); println!(" `let _ =` 之后(临时值已经 drop)"); let _keep = D("绑定"); println!(" `let _keep =` 之后(还没 drop)"); }
13 | }
编译:成功;警告:
warning: fields `first` and `second` are never read
--> <实验目录>/src/u55a.rs:3:15
|
3 | struct Pair { first: D, second: D }
| ---- ^^^^^ ^^^^^^
| |
| fields in this struct
|
= note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
warning: 1 warning emitted
运行(退出码 0):
-- 局部变量
drop c
drop b
drop a
-- 结构体字段
drop p.first
drop p.second
-- Vec 元素
drop v0
drop v1
drop v2
-- 临时值在语句结束时 drop
drop 临时
`let _ =` 之后(临时值已经 drop)
`let _keep =` 之后(还没 drop)
drop 绑定所有权与移动见Move 语义真实验证。
源码:
1 | struct D(&'static str);
2 | impl Drop for D { fn drop(&mut self) { println!(" drop {}", self.0); } }
3 | fn main() {
4 | let a = D("early"); println!("drop(a) 之前"); drop(a); println!("drop(a) 之后");
5 | let f = D("forgotten"); std::mem::forget(f); println!("forget 之后:不会看到 drop forgotten");
6 | let _end = D("end");
7 | }
编译:成功
运行(退出码 0):
drop(a) 之前
drop early
drop(a) 之后
forget 之后:不会看到 drop forgotten
drop end
源码:
1 | struct D;
2 | impl Drop for D { fn drop(&mut self) { println!("drop"); } }
3 | fn main() { let d = D; d.drop(); }
编译:失败
error[E0040]: explicit use of destructor method
--> <实验目录>/src/u55c.rs:3:26
|
3 | fn main() { let d = D; d.drop(); }
| ^^^^ explicit destructor calls not allowed
|
help: consider using `drop` function
|
3 - fn main() { let d = D; d.drop(); }
3 + fn main() { let d = D; drop(d); }
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0040`. 源码:
1 | struct D(&'static str);
2 | impl Drop for D { fn drop(&mut self) { println!(" drop {}", self.0); } }
3 | fn consume(d: D) { println!(" consume 里拿到 {}", d.0); }
4 | fn main() {
5 | let a = D("a"); consume(a);
6 | let b = D("b");
7 | if std::env::args().count() > 5 { consume(b); } else { println!(" 没有移动 b"); }
8 | println!("main 结束");
9 | }
编译:成功
运行(退出码 0):
consume 里拿到 a
drop a
没有移动 b
main 结束
drop b 编译:成功
运行(退出码 101):
即将 panic
drop guard
thread 'main' (7054972) panicked at <实验目录>/src/u55e.rs:3:58:
boom
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
源码:持有 D("guard") 后 panic!("boom")
stdout: 即将 panic | drop guard
stderr 第一行: ["thread 'main' (7054972) panicked at <实验目录>/src/u55e.rs:3:58:", 'boom']
编译:成功
运行(退出码 0):
即将 exit
process::exit 版本的 stdout: 即将 exit (没有 drop guard)panic 的展开机制不在这篇范围,这里只验证了 drop 是否运行。