目录
思维导图
1. 引用与借用的基本概念
1.1. 引用示例
2. 借用的规则
2.1. 可变借用示例
2.2. 借用的限制
3. 引用的生命周期
思维导图
1. 引用与借用的基本概念
- 引用的定义:引用是一种指向数据的指针,但与裸指针不同,Rust的引用在编译时受到严格的规则约束,确保其始终指向有效的内存区域。引用分为不可变引用(
&T
)和可变引用(&mut T
)。 - 借用的意义:借用是指在不获取数据所有权的情况下,通过引用访问或修改数据的过程。借用机制允许在多个上下文中共享数据,同时避免数据竞争和内存安全问题。
1.1. 引用示例
- 示例1:计算字符串长度
fn main() { let text = String::from("hello"); let length = calculate_string_length(&text); // 传递不可变引用 println!("The length of '{}' is {}.", text, length); } // 计算字符串长度的函数 fn calculate_string_length(s: &String) -> usize { s.len() // 通过引用访问数据 }
- 在这个示例中,
calculate_string_length
函数接受一个字符串的引用&text
,而不是直接获取String
的所有权。这允许main
函数在调用后继续使用text。
- 在这个示例中,
2. 借用的规则
- 不可变借用:当一个值被不可变引用借用时,该值在借用期间不能被修改。允许多个不可变引用同时存在,确保数据的一致性。
- 可变借用:若要修改借用的值,必须使用可变引用
&mut
。Rust强制要求在同一时间只能有一个可变引用,或者多个不可变引用,但两者不能共存。这一规则防止了数据竞争的发生。
2.1. 可变借用示例
- 示例2:修改借用的字符串
fn main() { let mut s = String::from("hello"); append_text(&mut s); // 传递可变引用 println!("{}", s); // 输出修改后的字符串 } // 修改字符串的函数 fn append_text(s: &mut String) { s.push_str(", world"); // 通过可变引用修改数据 }
- 在这个示例中,
s
被声明为可变,并通过&mut s
传递给append_text
函数,允许对s
进行修改。
- 在这个示例中,
2.2. 借用的限制
- 多个可变引用的限制:Rust禁止在同一作用域内同时存在多个可变引用,以防止数据竞争(data races)。数据竞争可能导致未定义行为,因此Rust在编译时严格检查此类问题。
- 可变与不可变引用的限制:当同一个值有一个不可变引用时,便不能再拥有一个可变引用。
- 示例3:多个可变引用的错误
fn main() { let mut message = String::from("hello"); let first_ref = &mut message; // 第一个可变引用 // let second_ref = &mut message; // 取消注释会导致编译错误 println!("First reference: {}", first_ref); // println!("Second reference: {}", second_ref); // 无法同时使用两个可变引用 }
- 此代码尝试同时创建两个可变引用,导致编译错误。
3. 悬空引用
-
Rust通过生命周期(lifetime)机制确保引用在使用期间始终指向有效的内存区域,避免了悬空引用的问题。生命周期是Rust编译器在编译时进行静态检查的重要工具。
- 示例4:悬空引用的错误
fn main() { // let dangling_ref = create_dangling_reference(); // 取消注释会导致编译错误 // println!("{}", dangling_ref); // 无法使用悬空引用 } // 尝试返回局部变量引用的函数 fn create_dangling_reference() -> &String { let s = String::from("hello"); &s // 编译错误:返回局部变量的引用 }
- 该示例试图返回一个局部变量的引用,导致编译错误,因为
&s
在函数结束后S
会被释放。
- 该示例试图返回一个局部变量的引用,导致编译错误,因为
tips:
- 在任何时候,你都可以拥有要么一个可变引用要么任意数量的不可变引用。
- 引用必须始终有效。
补充:常见数据竞争:
- 两个或多个指针同时访问相同的数据。
- 至少有一个指针正在用于写入数据。
- 没有使用任何机制来同步对数据的访问。