所有权与移动

RustRustBeginner
立即练习

This tutorial is from open-source community. Access the source code

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本实验中,将解释在 Rust 中,变量拥有资源的所有权,并且只能有一个所有者,这可防止资源被多次释放。当通过值来赋值变量或传递函数参数时,资源的所有权会被转移,这称为移动。移动之后,先前的所有者不能再使用,以避免创建悬空指针。代码示例通过展示栈分配和堆分配变量的所有权如何转移,以及在变量所有权被移动后访问该变量如何导致错误,来演示这些概念。

注意:如果实验未指定文件名,你可以使用任何你想要的文件名。例如,你可以使用 main.rs,并通过 rustc main.rs &&./main 来编译和运行它。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/MemorySafetyandManagementGroup(["Memory Safety and Management"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/DataTypesGroup -.-> rust/integer_types("Integer Types") rust/DataTypesGroup -.-> rust/type_casting("Type Conversion and Casting") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/MemorySafetyandManagementGroup -.-> rust/lifetime_specifiers("Lifetime Specifiers") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-99195{{"所有权与移动"}} rust/integer_types -.-> lab-99195{{"所有权与移动"}} rust/type_casting -.-> lab-99195{{"所有权与移动"}} rust/function_syntax -.-> lab-99195{{"所有权与移动"}} rust/expressions_statements -.-> lab-99195{{"所有权与移动"}} rust/lifetime_specifiers -.-> lab-99195{{"所有权与移动"}} rust/method_syntax -.-> lab-99195{{"所有权与移动"}} rust/operator_overloading -.-> lab-99195{{"所有权与移动"}} end

所有权与移动

由于变量负责释放其自身的资源,资源只能有一个所有者。这也可防止资源被释放多次。请注意,并非所有变量都拥有资源(例如,[引用])。

在进行赋值(let x = y)或按值传递函数参数(foo(x))时,资源的所有权会被转移。在 Rust 中,这被称为移动

在移动资源之后,先前的所有者不能再被使用。这可避免创建悬空指针。

// 此函数获取堆分配内存的所有权
fn destroy_box(c: Box<i32>) {
    println!("Destroying a box that contains {}", c);

    // `c` 被销毁且内存被释放
}

fn main() {
    // 栈分配的整数
    let x = 5u32;

    // 将 `x` **复制** 到 `y` - 没有资源被移动
    let y = x;

    // 两个值都可以独立使用
    println!("x is {}, and y is {}", x, y);

    // `a` 是指向堆分配整数的指针
    let a = Box::new(5i32);

    println!("a contains: {}", a);

    // 将 `a` **移动** 到 `b`
    let b = a;
    // `a` 的指针地址被复制(而非数据)到 `b` 中。
    // 两者现在都是指向同一堆分配数据的指针,但
    // `b` 现在拥有它。

    // 错误!`a` 不能再访问数据,因为它不再拥有
    // 堆内存
    //println!("a contains: {}", a);
    // TODO ^ 尝试取消注释此行

    // 此函数从 `b` 获取堆分配内存的所有权
    destroy_box(b);

    // 由于此时堆内存已被释放,此操作将
    // 导致解引用已释放的内存,但这被编译器禁止
    // 错误!与上一个错误原因相同
    //println!("b contains: {}", b);
    // TODO ^ 尝试取消注释此行
}

总结

恭喜你!你已完成“所有权与移动”实验。你可以在 LabEx 中练习更多实验以提升你的技能。