Rust 的所有权和借用类似于借书系统,包括所有权转移、不可变和可变借用、悬垂引用防止机制,以及在函数中传递和返回所有权的规则。
在 Rust 的世界里,所有权和借用就像是图书馆的借书系统。今天,我们就来聊聊这些概念,看看它们是如何在 Rust 中发挥作用的。
想象一下,你有一本书,这本书就是你的所有权。你可以读它、写它、甚至卖掉它。在 Rust 中,变量就像这本书,拥有它的所有权。你可以通过 let
关键字来声明这本书:
let my_book = String::from("Rust Programming");
这里,my_book
就是你的书,它拥有字符串 "Rust Programming"
的所有权。
有时候,你会把书借给朋友读。在 Rust 中,这就是“借用”。通过 &
符号,你可以把书的借阅卡(引用)借给朋友,但书还是你的:
let borrowed_book: &String = &my_book;
这里的 borrowed_book
就是借阅卡,它可以访问 my_book
的内容,但并不拥有它。
当朋友拿到借阅卡后,他可能会把书的内容分享给别人:“看,我借到了一本超棒的书!” 在 Rust 中,这就是“解引用”。通过 *
符号,你可以获取借用的对象的值:
println!("My book: {}, Borrowed book: {}", my_book, *borrowed_book);
这里的 *borrowed_book
就是朋友分享的书,它展示了 my_book
的内容。
借用分为两种:不可变引用和可变引用。不可变引用就像你借给朋友的书,他只能读,不能写:
fn read_book(book: &String) -> usize {
book.len()
}
而可变引用则允许朋友在书上做笔记:
fn write_in_book(book: &mut String) {
book.push_str(" - Notes by friend");
}
有时候,朋友借了你的书,结果你突然把书销毁了,这就会导致“悬垂引用”。Rust 会在编译时就阻止这种情况发生:
fn dangling_reference() -> &String {
let book = String::from("Rust Programming");
&book
} // 离开函数体作用域后,变量 book 的内存空间会被自动释放掉,此时 &book 成为悬垂引用
所有权可以转移给函数,就像你把书送给朋友。在函数中,书会被“释放”(dropped):
fn give_book(book: String) {
println!("Given book: {}", book);
// book 在这里被 dropped 释放
}
fn main() {
let my_book = String::from("Rust Programming");
// my_book 的所有权被移交至 give_book 函数
give_book(my_book);
// 此后 my_book 便无法再被使用
}
在可变借用后,你不能再次借用或修改书,这是为了避免数据争用:
fn main() {
let mut my_book = String::from("Rust Programming");
let borrowed_book = &mut my_book;
// 以下代码会报错
// give_book(my_book); // 无法移交所有权,因为已经被可变借用
// my_book.push_str(" - New Chapter"); // 无法修改,因为已经被可变借用
borrowed_book.push_str(" - Notes by friend");
println!("Updated book: {}", borrowed_book);
// borrowed_book 会因为此后不再被使用而被 dropped 释放
// 现在修改可以正常进行,因为所有可变引用已经被 dropped 释放
my_book.push_str(" - Final Chapter");
println!("Final book: {}", my_book);
}
释放结构体时,Rust 会先释放父结构体,再释放子结构体:
struct Chapter {
content: String,
}
struct Book {
title: String,
chapter: Chapter,
}
fn main() {
let my_book = Book {
title: String::from("Rust Programming"),
chapter: Chapter {
content: String::from("Chapter 1: Ownership"),
},
};
println!("Book: {}, Chapter: {}", my_book.title, my_book.chapter.content);
// my_book 首先被 dropped 释放
// 紧接着是 my_book.chapter
}
你也可以从函数中获取一本书的所有权:
fn create_book() -> Book {
Book {
title: String::from("Rust Essentials"),
chapter: Chapter {
content: String::from("Chapter 1: Borrowing"),
},
}
}
fn main() {
let new_book = create_book();
println!("New book: {}, Chapter: {}", new_book.title, new_book.chapter.content);
// new_book 成为了所有者
// new_book 在函数域结尾被 dropped 释放
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!