核心概念
-
所有权(Ownership)
- 规则:
- Rust中每个值有且只有一个所有者(Owner)
- 当所有者离开作用域,值会被自动释放
- 赋值操作(如
let a = b)可能转移所有权(Move)而非复制
- 示例:
let s1 = String::from("hello"); // s1拥有字符串 let s2 = s1; // 所有权转移给s2 // println!("{}", s1); // 错误!s1不再有效
- 规则:
-
借用(Borrowing)
- 通过引用(
&)借用数据,不获取所有权 - 规则:
- 同一时间,要么只能有一个可变引用(
&mut),要么有多个不可变引用(&) - 引用必须始终有效(悬垂引用禁止)
- 同一时间,要么只能有一个可变引用(
- 示例:
let mut s = String::from("hello"); let r1 = &s; // 不可变引用 let r2 = &s; // 允许第二个不可变引用 // let r3 = &mut s; // 错误!已有不可变引用存在
- 通过引用(
-
生命周期(Lifetime)
- 确保引用始终指向有效数据
- 编译器会自动推断大多数情况,复杂场景需要手动标注
练习题
题目1:计算字符串长度的函数
fn calculate_length(s: &String) -> usize {
s.len() // 返回长度,不获取所有权
}
fn main() {
let s = String::from("ownership");
let len = calculate_length(&s);
println!("'{}'的长度是{}", s, len); // 正确:s仍有效
}
题目2:触发所有权错误
fn main() {
let s1 = String::from("hello");
let s2 = s1; // 所有权转移
println!("{}", s1); // 故意触发错误
}
- 编译后会看到错误信息:
borrow of moved value: 's1' - 修复方法:使用克隆(
let s2 = s1.clone();)
题目3:结构体与方法
struct Person {
name: String,
age: u8,
}
impl Person {
// 方法:不可变借用
fn introduce(&self) {
println!("我叫{},今年{}岁", self.name, self.age);
}
// 方法:可变借用修改年龄
fn birthday(&mut self) {
self.age += 1;
}
}
fn main() {
let mut bob = Person {
name: String::from("Bob"),
age: 30,
};
bob.introduce(); // 输出:我叫Bob,今年30岁
bob.birthday(); // 修改年龄
bob.introduce(); // 输出:我叫Bob,今年31岁
}
常见问题解决
-
错误:
cannot borrow 'x' as mutable more than once at a time- 原因:同时存在多个可变引用
- 修复:限制作用域
let mut s = String::from("hello"); { let r1 = &mut s; } // r1离开作用域 let r2 = &mut s; // 允许
-
错误:
missing lifetime specifier- 原因:结构体包含引用但未指定生命周期
- 修复(后续阶段会深入):
struct Book<'a> { title: &'a str, // 显式标注生命周期 }