====== 引用、借用与生命周期 ======
===== 引用和借用 =====
**引用(Reference)** 允许在不转移所有权的情况下访问值。创建引用称为**借用(Borrowing)**。
==== 不可变引用 ====
fn main() {
let s = String::from("hello");
fn len(s: &String) -> usize {
s.len() // 借用 s,不拥有所有权
} // s 没有释放
let length = len(&s);
println!("'{}' 的长度是 {}", s, length); // s 仍然可用
}
**规则**:不可变引用可同时有多个。
fn main() {
let s = String::from("hello");
let r1 = &s;
let r2 = &s; // 多个不可变引用 OK
println!("{}, {}", r1, r2);
}
==== 可变引用 ====
fn main() {
let mut s = String::from("hello");
fn change(s: &mut String) {
s.push_str(", world");
}
change(&mut s);
println!("{}", s); // "hello, world"
}
**规则**:同一时间只能有一个可变引用。
fn main() {
let mut s = String::from("hello");
let r1 = &mut s;
// let r2 = &mut s; // 编译错误:不能同时有两个可变引用
println!("{}", r1);
}
==== 引用规则总结 ====
* 同一个作用域中,一个值可以有多个不可变引用(''&T'')
* 同一个作用域中,一个值只能有一个可变引用(''&mut T'')
* 可变引用和不可变引用不能共存
* 引用必须始终有效(不会出现悬垂引用)
fn main() {
let mut s = String::from("hello");
let r1 = &s; // OK
let r2 = &s; // OK
// let r3 = &mut s; // 编译错误:已有不可变引用
println!("{}, {}", r1, r2);
// r1 和 r2 不再使用
let r3 = &mut s; // 现在 OK
r3.push_str("!");
println!("{}", r3);
}
===== 字符串切片(Slice) =====
切片是对集合一部分的引用:
fn main() {
let s = String::from("hello world");
let hello = &s[0..5]; // "hello"
let world = &s[6..11]; // "world"
println!("{}, {}", hello, world);
}
==== 字符串切片类型 &str ====
fn main() {
let s = String::from("hello world");
// 取前5个字符
let slice1 = &s[..5]; // 等同于 &s[0..5]
let slice2 = &s[6..]; // 等同于 &s[6..len]
let slice3 = &s[..]; // 整个字符串
println!("{} {} {}", slice1, slice2, slice3);
}
==== 数组切片 ====
fn main() {
let arr = [1, 2, 3, 4, 5];
let slice = &arr[1..3]; // [2, 3]
println!("{:?}", slice);
}
===== 生命周期简介 =====
生命周期(Lifetimes)确保引用始终有效。多数情况下编译器可以自动推断。
==== 生命周期注解语法 ====
// 'a 是生命周期参数,标明 x 和 y 必须活得一样长
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
fn main() {
let s1 = String::from("长字符串");
let s2 = String::from("短");
let result = longest(&s1, &s2);
println!("较长的: {}", result);
}
==== 结构体中的生命周期 ====
struct Excerpt<'a> {
part: &'a str, // 结构体包含引用时必须标注生命周期
}
fn main() {
let novel = String::from("很久很久以前...");
let first = novel.split('.').next().expect("没有找到");
let excerpt = Excerpt { part: first };
println!("{}", excerpt.part);
}
==== 静态生命周期 ====
'''static'' 生命周期在整个程序运行期间有效:
// 字符串字面量有 'static 生命周期
let s: &'static str = "我存在于整个程序运行期间";
===== 本章小结 =====
* 引用允许访问值而不转移所有权
* 同一时间要么多个不可变引用,要么一个可变引用
* 切片是对集合部分元素的引用
* 生命周期注解确保引用不会悬垂
* ''&'static'' 表示整个程序都有效的引用