大家好,
今天是我学 Rust 的第7天,今天我要来看一下引用和借用。昨天我学习了 Rust 的所有权模型,如果你对 Rust 一无所知的话,那篇文章是必读的。
引用
昨天我们看到,将参数传递给函数与将值赋给另一个变量产生了相同的效果,实际上导致了所有权的丧失。不过,有一个解决方法。
如果你了解 C 语言,指针
是 C 语言的一个重要概念。而引用与之类似。
让我们看一下代码并理解它:
rust
fn main(){
let s1: String = String::from("Hello World");
let length: usize = calculate_length(&s1); // & 用于传递字符串的引用
println!("`{}` 的长度为 {}" ,s1,length);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
Rust 中的引用是指针,允许借用和访问数据而不转移所有权,有助于内存安全,防止数据竞争。
解释:
fn main()
: 程序的入口点。let s1: String = String::from("Hello World");
: 声明一个 String 变量s1
,值为 "Hello World"。let length: usize = calculate_length(&s1);
: 调用calculate_length
函数,传递对字符串s1
的引用。fn calculate_length(s: &String) -> usize
: 函数以对 String 的引用 (&String
) 作为参数,并返回它的长度作为usize
类型。s.len()
: 获取引用s
所指向的 String 的长度。println!("
{}的长度为 {}" ,s1, length);
: 打印原始字符串s1
及其长度。
关键概念:
&
用于传递对字符串的引用 (&s1
),而不是转移所有权,防止字符串被移动或克隆。- 这种借用允许
calculate_length
函数在不获取所有权的情况下操作字符串。 - 引用默认为不可变。
感谢 Let's Get Rusty
在他的 YouTube 频道上提供这么棒的解释。
可变引用
我们上面看到的是不可变引用,我们无法真正改变值,但我们可以从中读取。让我们来看看 可变引用
。
rust
fn main() {
let mut s1 = String::from("Hello");
// 传递可变引用给 modify_string 函数
modify_string(&mut s1);
// 原始字符串现在被修改了
println!("修改后的字符串: {}", s1);
}
fn modify_string(s: &mut String) {
s.push_str(", World!"); // 通过追加来修改字符串
}
解释:
fn main()
: 程序的入口点。let mut s1 = String::from("Hello");
: 声明一个可变的 String 变量s1
。modify_string(&mut s1);
: 调用modify_string
函数,传递对s1
的可变引用。fn modify_string(s: &mut String)
: 函数以对 String 的可变引用 (&mut String
) 作为参数。s.push_str(", World!");
: 通过追加将 ", World!" 添加到s
所指向的字符串。println!("修改后的字符串: {}", s1);
: 打印修改后的字符串。
关键概念:
- 可变引用可以通过
&mut 变量名
进行传递。
可变引用的规则
- 对于特定数据片段,只允许一个可变引用或多个不可变引用。
- 在可变引用有效时,不允许对相同数据进行其他引用。
- 可变引用受其作用域的约束,防止悬空引用。
- 在特定作用域内只能存在一个可变引用,以确保协调的修改。
简单来说,一个特定作用域内只能存在一个对变量的可变引用。
虽然不可变引用的数量可以是无限的。
但是,不可变和可变引用可以同时存在于相同的作用域内。
示例:
rust
fn main(){
let mut string1: String = String::from("Hello World");
let reference1: &String = &string1;
let reference2: &String = &string1;
takes_ownership(reference1);
takes_ownership(reference2);
let _mut_ref: &mut String = &mut string1;
}
fn takes_ownership(_r1: &String){
}
这个例子完全没问题,因为在我们创建 _mut_ref
时,reference1
和 reference2
已经超出了作用域。
rust
// 这段代码会导致错误
fn main(){
let mut string1: String = String::from("Hello World");
let reference1: &String = &string1;
let reference2: &String = &string1;
// 因为这一行
let _mut_ref: &mut String = &mut string1;
takes_ownership(reference1);
takes_ownership(reference2);
}
fn takes_ownership(_r1: &String){
}
结论
在学习 Rust 的旅程中,第7天探讨了引用和借用,这是内存安全的基本概念。不可变引用允许在不转移所有权的情况下读取数据,而可变引用则允许修改,但必须遵守规则以确保独占访问和防止数据