引用(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); }
切片是对集合一部分的引用:
fn main() { let s = String::from("hello world"); let hello = &s[0..5]; // "hello" let world = &s[6..11]; // "world" println!("{}, {}", hello, world); }
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 表示整个程序都有效的引用