【Rust 基础入门】(05) | 借用、所有权与函数

  • 0xE
  • 更新于 2天前
  • 阅读 256

Rust 的所有权和借用类似于借书系统,包括所有权转移、不可变和可变借用、悬垂引用防止机制,以及在函数中传递和返回所有权的规则。

在 Rust 的世界里,所有权和借用就像是图书馆的借书系统。今天,我们就来聊聊这些概念,看看它们是如何在 Rust 中发挥作用的。

1. 所有权:你有一本书

想象一下,你有一本书,这本书就是你的所有权。你可以读它、写它、甚至卖掉它。在 Rust 中,变量就像这本书,拥有它的所有权。你可以通过 let 关键字来声明这本书:

let my_book = String::from("Rust Programming");

这里,my_book 就是你的书,它拥有字符串 "Rust Programming" 的所有权。

2. 借用:朋友借你的书

有时候,你会把书借给朋友读。在 Rust 中,这就是“借用”。通过 & 符号,你可以把书的借阅卡(引用)借给朋友,但书还是你的:

let borrowed_book: &String = &my_book;

这里的 borrowed_book 就是借阅卡,它可以访问 my_book 的内容,但并不拥有它。

3. 解引用:朋友分享你的书

当朋友拿到借阅卡后,他可能会把书的内容分享给别人:“看,我借到了一本超棒的书!” 在 Rust 中,这就是“解引用”。通过 * 符号,你可以获取借用的对象的值:

println!("My book: {}, Borrowed book: {}", my_book, *borrowed_book);

这里的 *borrowed_book 就是朋友分享的书,它展示了 my_book 的内容。

4. 不可变引用与可变引用

借用分为两种:不可变引用和可变引用。不可变引用就像你借给朋友的书,他只能读,不能写:

fn read_book(book: &String) -> usize {
    book.len()
}

而可变引用则允许朋友在书上做笔记:

fn write_in_book(book: &mut String) {
    book.push_str(" - Notes by friend");
}

5. 悬垂引用:书被销毁了

有时候,朋友借了你的书,结果你突然把书销毁了,这就会导致“悬垂引用”。Rust 会在编译时就阻止这种情况发生:

fn dangling_reference() -> &String {
    let book = String::from("Rust Programming");
    &book
} // 离开函数体作用域后,变量 book 的内存空间会被自动释放掉,此时 &book 成为悬垂引用

6. 所有权与函数

所有权可以转移给函数,就像你把书送给朋友。在函数中,书会被“释放”(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 便无法再被使用
}

7. 可变借用的限制

在可变借用后,你不能再次借用或修改书,这是为了避免数据争用:

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);
}

8. 分级释放

释放结构体时,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
}

9. 从函数中获取所有权

你也可以从函数中获取一本书的所有权:

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 释放
}
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
0xE
0xE
0x59f6...a17e
17年进入币圈,Web3 开发者。刨根问底探链上真相,品味坎坷悟 Web3 人生。工作机会可加v:__0xE__