📜  Rust——所有权的概念

📅  最后修改于: 2022-05-13 01:55:15.765000             🧑  作者: Mango

Rust——所有权的概念

Rust 编程语言以其内存管理而闻名。本文解释了 Rust 如何使用其所有权模型来更好地管理内存。如果您想在阅读本文之前回顾一下 Rust 语法,您可以参考 Rust 档案。

通常,通过使用垃圾收集(或)程序员必须明确定义内存使用情况,有两种方法可以在程序中管理内存。这两个选项都有其优点和缺点,例如显式管理速度更快,但垃圾收集更容易实现。 Rust 遵循一种称为“所有权”的新方法,该方法有望更快,并且当您习惯它时会更容易。所有权模型对程序员来说是新的,但是当您理解并开始练习时,您可以更好地使用它。

什么是内存安全?

内存安全是程序的属性,其中内存指针始终用于指向正确类型和大小的有效内存。内存不安全的程序可能会崩溃或产生意外的输出和错误。它还可能导致数据泄漏,从而降低程序的安全性。可能导致内存安全问题的示例之一是悬空指针(指向无效数据(或)空值的指针)。

堆栈和堆

Rust 将原始数据类型直接存储到内存中,但复杂数据类型通常存储在堆栈(或)堆中。

堆栈在编译时存储大小的变量。堆栈遵循后进先出的顺序。所有标量类型都可以存储在堆栈中,因为大小是固定的。如果在编译时变量的大小未知,那么它们将存储在适合动态数据类型的堆中。堆分配用于存储在程序的整个生命周期中可能会更改的变量。由于固定大小和直接访问,在堆栈上执行操作比堆更快。



Rust 所有权规则

Rust 所有权规则是所有权模型的指南(或)标准。这些是

  • Rust 中的每个值都有一个称为其所有者的变量。
  • 一次只能有一个所有者。
  • 当所有者超出范围时,该值将被删除。

这是一个遵循上述规则的简单 Rust 程序

Rust
fn main() {
    print_gfg()
}
  
// gfg is not declared
fn print_gfg(){
    
   //gfg declared and its validity starts
    let gfg = "GeeksForGeeks";  
    
    // gfg is in scope so valid
    println!("{}",gfg); 
}


Rust
fn main() {
    print_gfg()
}
  
// gfg is not declared
fn print_gfg(){
    
    //gfg declared and its validity starts
    let gfg = "Geeks"; 
    
    // gfg1 copies the data in variable gfg
    let gfg1 = gfg;     
    
    // gfg, gfg1 are in scope so valid
    println!("{} For {}",gfg, gfg1); 
} //gfg, gfg1 both go out of scope


Rust
fn main() {
    print_gfg()
}
  
fn print_gfg(){
    let gfg = String::from("Geeks");  
    let gfg1 = gfg;
    println!("{} For {}",gfg, gfg1);
}


Rust
fn main() {
    print_gfg()
}
  
fn print_gfg(){
    let gfg = String::from("Geeks");  
    let gfg1 = gfg.clone();
    println!("{} For {}",gfg, gfg1);
}


输出:

GeekdForGeeks

让我们看一下这个程序。 main函数只有一行调用print_gfg()函数。 print_gfg()函数打印出字符串“GeeksForGeeks”。我们使用变量“gfg”来存储字符串“GeeksForGeeks”,所以gfg将成为字符串,并且因为它在 print_gfg()函数声明,它是所有者且有效的变量的范围直到结束函数。

铁锈所有权

多个变量和数据

在上面的程序中,我们已经看到了变量如何访问数据,现在我们将看到多个如何与相同数据交互的示例。

fn main() {
    print_gfg()
}
  
// gfg is not declared
fn print_gfg(){
    
    //gfg declared and its validity starts
    let gfg = "Geeks"; 
    
    // gfg1 copies the data in variable gfg
    let gfg1 = gfg;     
    
    // gfg, gfg1 are in scope so valid
    println!("{} For {}",gfg, gfg1); 
} //gfg, gfg1 both go out of scope

在这个程序中,变量 gfg1 复制了变量 gfg 中的数据,但它是有效的,因为在编译之前变量的大小是已知的,所以 Rust 将变量存储在堆栈中。

程序有效

现在让我们看一个程序,其中数据存储在堆中,并尝试将该数据复制到另一个变量

fn main() {
    print_gfg()
}
  
fn print_gfg(){
    let gfg = String::from("Geeks");  
    let gfg1 = gfg;
    println!("{} For {}",gfg, gfg1);
}

这会产生错误,因为gfg变量的大小在编译时是未知的,当我们将 gfg1 引用到gfg 时,指针从gfg移动到 gfg1 而不是复制。要使其复制数据而不是移动数据,需要使用 clone 方法

fn main() {
    print_gfg()
}
  
fn print_gfg(){
    let gfg = String::from("Geeks");  
    let gfg1 = gfg.clone();
    println!("{} For {}",gfg, gfg1);
}


克隆

你可以从 References 和 Borrowing 中了解更多关于 Rust 如何处理多个数据变量的信息