把引用存进结构体是 Rust 里「零拷贝」的主要手段,也是生命周期标注最常出现的地方。这篇验证它的语法要求、它对数据寿命和修改的限制,并用一个自定义的计数分配器量出它省下了多少堆分配。
源码:
1 | struct Excerpt { part: &str }
2 | fn main() {}
编译:失败
error[E0106]: missing lifetime specifier
--> <实验目录>/src/u25a.rs:1:24
|
1 | struct Excerpt { part: &str }
| ^ expected named lifetime parameter
|
help: consider introducing a named lifetime parameter
|
1 | struct Excerpt<'a> { part: &'a str }
| ++++ ++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0106`.
源码:
1 | struct Excerpt<'a> { part: &'a str }
2 | fn main() {
3 | let novel = String::from("Call me Ishmael. Some years ago...");
4 | let first = novel.split('.').next().unwrap();
5 | let e = Excerpt { part: first };
6 | println!("摘录:{}", e.part);
7 | }
编译:成功
运行(退出码 0):
摘录:Call me Ishmael 源码:
1 | struct Excerpt<'a> { part: &'a str }
2 | fn main() {
3 | let e;
4 | {
5 | let novel = String::from("Call me Ishmael.");
6 | e = Excerpt { part: &novel[..4] };
7 | }
8 | println!("{}", e.part);
9 | }
编译:失败
error[E0597]: `novel` does not live long enough
--> <实验目录>/src/u25c.rs:6:30
|
5 | let novel = String::from("Call me Ishmael.");
| ----- binding `novel` declared here
6 | e = Excerpt { part: &novel[..4] };
| ^^^^^ borrowed value does not live long enough
7 | }
| - `novel` dropped here while still borrowed
8 | println!("{}", e.part);
| ------ borrow later used here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0597`.
源码:
1 | struct Excerpt<'a> { part: &'a str }
2 | fn main() {
3 | let mut novel = String::from("Call me Ishmael.");
4 | let e = Excerpt { part: &novel[..4] };
5 | novel.push_str(" Some years ago");
6 | println!("{}", e.part);
7 | }
编译:失败
error[E0502]: cannot borrow `novel` as mutable because it is also borrowed as immutable
--> <实验目录>/src/u25d.rs:5:5
|
4 | let e = Excerpt { part: &novel[..4] };
| ----- immutable borrow occurs here
5 | novel.push_str(" Some years ago");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
6 | println!("{}", e.part);
| ------ immutable borrow later used here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0502`. 源码:
1 | use std::alloc::{GlobalAlloc, Layout, System};
2 | use std::sync::atomic::{AtomicUsize, Ordering};
3 | struct Counting;
4 | static ALLOCS: AtomicUsize = AtomicUsize::new(0);
5 | unsafe impl GlobalAlloc for Counting {
6 | unsafe fn alloc(&self, l: Layout) -> *mut u8 { ALLOCS.fetch_add(1, Ordering::Relaxed); unsafe { System.alloc(l) } }
7 | unsafe fn dealloc(&self, p: *mut u8, l: Layout) { unsafe { System.dealloc(p, l) } }
8 | }
9 | #[global_allocator] static A: Counting = Counting;
10 |
11 | struct Tokens<'a> { words: Vec<&'a str> } // 借用:切片指回原文
12 | struct OwnedTokens { words: Vec<String> } // 拥有:每个词一个 String
13 | fn main() {
14 | let text: String = (0..10_000).map(|i| format!("word{i} ")).collect();
15 | let before = ALLOCS.load(Ordering::Relaxed);
16 | let t = Tokens { words: text.split_whitespace().collect() };
17 | let a1 = ALLOCS.load(Ordering::Relaxed) - before;
18 | let before = ALLOCS.load(Ordering::Relaxed);
19 | let o = OwnedTokens { words: text.split_whitespace().map(String::from).collect() };
20 | let a2 = ALLOCS.load(Ordering::Relaxed) - before;
21 | println!("文本里有 {} 个词", t.words.len());
22 | println!("借用版(Vec<&str>) 堆分配 {} 次", a1);
23 | println!("拥有版(Vec<String>)堆分配 {} 次", a2);
24 | println!("第 5000 个词:{} / {};两者内容相同:{}", t.words[5000], o.words[5000], t.words[5000] == o.words[5000]);
25 | }
编译:成功
运行(退出码 0):
文本里有 10000 个词
借用版(Vec<&str>) 堆分配 13 次
拥有版(Vec<String>)堆分配 10013 次
第 5000 个词:word5000 / word5000;两者内容相同:true分配次数通过自定义 #[global_allocator] 计数得到(只数 alloc 次数,不含字节数);release 构建。自定义分配器相关的更多内容这里没有展开。
源码:
1 | struct Pair<'a, 'b> { left: &'a str, right: &'b str }
2 | fn main() {
3 | let a = String::from("长寿的");
4 | let p;
5 | {
6 | let b = String::from("短命的");
7 | let tmp = Pair { left: &a, right: &b };
8 | println!("内层:{} {}", tmp.left, tmp.right);
9 | p = tmp.left; // 只取出生命周期 'a 的那部分
10 | }
11 | println!("外层:{}", p);
12 | }
编译:成功
运行(退出码 0):
内层:长寿的 短命的
外层:长寿的