【Rust 中级教程】 10 所有权(3)

简介: 【Rust 中级教程】 10 所有权(3)

0x00 开篇


上一篇文章介绍了所有权在变量间赋值的转移操作,以及详细对比了与其它语言的异同。本篇文章将继续介绍另外两种转移操作——向函数传递值和从函数返回值。本篇文章的阅读时间大约 8 分钟。


0x01 转移——向函数传递值


先上代码:

fn main() {
    let name = String::from("ZhangSan");
    print_name(name);
    println!("{}", name);
}
fn print_name(name: String) {
    println!("My name is {}", name);
}

如果用目前大部分的主流代码的思想去看上面的代码,都会认为没有问题。但是在 Rust 中,它则会编译失败。


0a2653c851af460fa595bd959398a8f1.png


失败的错误与上一篇文章介绍的变量赋值一样。当我们把外部的变量传递到函数内部时,外部变量的所有权将会转移到函数内部。此时,外部将无法再次使用该变量了。j简易示意过程如下:


2d65d23f6d4748949b924e4057485923.png


向函数传值所有权转移 简易示意图


代码释义:

fn main() {
    // 1. 创建 name,name所有权在 main 函数作用域内
    let name = String::from("ZhangSan");
    // 2.
    // 2.1 将 name 以参数形式传递到 print_name 函数中
    // 2.2 name 离开 main 函数作用域,所有权转移到函数内部
    print_name(name);
    // 5.接下来 将无法再使用 name 变量
    // name 变为无效,下面的代码报错
    // println!("{}", name);
    // 运行结果
    // My name is ZhangSan
}
fn print_name(name: String) {
    // 3. name 进入 print_name 作用域, 外部将无法访问 name 变量
    println!("My name is {}", name);
} // 4. 函数结束,作用域失效,内存释放,name 变量也被释放


0x02 转移——从函数返回值


理解了向函数传递值的过程,那么从函数返回值也是同样的道理。


0a2653c851af460fa595bd959398a8f1.png


从函数返回值所有权转移 简易示意图


示例代码:

fn get_name() -> String {
    // 1. 函数内创建 name 变量
    let name = String::from("LiSi");
    return String::from("My name is ") + name.as_str();
} // 2. 作用域结束,内存释放,name释放,将返回值的所有权转移至调用者
fn main() {
  // 3. get_name 返回值的所有权转移至 name
    let name = get_name();
    // 4. 打印name
    println!("{}", name);
    // 运行结果
    // My name is LiSi
}


0x03 转移与流程控制


再来了解一些其它场景中使用转移。

 
条件语句


在条件语句中使用转移。由于分支语句肯定会执行一个分支,因此我们可以在每个分支中去使用变量,但只会在一个分支发生转移。

fn print_dance(name: String) {
    println!("{} 喜欢跳舞", name);
}
fn print_swim(name: String) {
    println!("{} 喜欢游泳", name);
}
fn main() {
  let x = 3 % 2;
    let name = String::from("小明");
    if x == 0 {
        print_dance(name)
    } else {
        print_swim(name)
    }
    // 无法再次使用 name
    // print_dance(name);
    // 运行结果
    // 小明 喜欢游泳
}
循环语句


由于循环体的特殊性,当第二次运行循环体时,上一次循环已经发生转移。所以下面的代码将会编译错误。

fn main() {
    let name = String::from("rust");
    for _ in 1..4 {
        // 下面的代码 是错误的
        // print_dance(name);
    }
}


模式匹配


模式匹配与分支语句类似,不再赘述了,直接看下代码吧。

fn main() {
    // 【匹配】
    let x = 3 % 2;
    let name = String::from("小明");
    match x {
        0 => {
            print_dance(name);
        }
        1 => {
            print_swim(name);
        }
        _ => {
            println!("{}", name);
        }
    };
    // 下面的代码 是错误的
    // println!("{}", name);
    // 运行结果
    // 小明 喜欢游泳
}


0x04 小结


有关 Rust 转移的特性基本已经介绍完了。我相信读完文章的你没有感觉到它有多难,只是觉得这样的设计很新奇。总结下 Rust 所有权的几个核心特点吧:

  • 所有权机制仅针对在堆上分配的数据,不包含基本类型。
  • 变量与值的关系是绑定关系,变量拥有值的所有权。反过来讲。每一个值都存在一个所有者。每块内存空间都存在一个所有者。
  • 当某一个变量离开当前所属的作用域后,变量将变为无效。
  • 转移通常发生在变量间的赋值、向函数传值、从函数返回值这三大场景。

从目前来讲,所有的值有且只有一个所有者。

相关文章
|
6月前
|
存储 Rust
【Rust】——所有权规则、内存分配
【Rust】——所有权规则、内存分配
|
3月前
|
存储 Rust 安全
30天拿下Rust之所有权
在编程语言的世界中,Rust凭借其独特的所有权机制脱颖而出,为开发者提供了一种新颖而强大的工具来防止内存错误。这一特性不仅确保了代码的安全性,还极大地提升了程序的性能。在Rust中,所有权是一种编译时检查机制,用于追踪哪些内存或资源何时可以被释放。每当一个变量被赋予一个值(比如:字符串、数组或文件句柄)时,Rust会确定这个变量是否“拥有”这个值,拥有资源的变量负责在适当的时候释放这些资源。
38 5
|
4月前
|
存储 Rust 安全
【Rust学习】04_所有权
所有权是 Rust 最独特的特性,对语言的其余部分有着深远的影响。它使 Rust 能够在不需要垃圾收集器的情况下保证内存安全,因此了解所有权的运作方式非常重要。在本章中,我们将讨论所有权以及几个相关功能:借用、切片以及 Rust 如何在内存中布局数据。
26 1
|
6月前
|
存储 Rust 安全
Rust 笔记:Rust 语言中的 所有权 与 生命周期
Rust 笔记:Rust 语言中的 所有权 与 生命周期
184 0
|
5月前
|
Rust 安全 开发者
Rust引用、借用和所有权详解
Rust引用、借用和所有权详解
|
6月前
|
Rust 算法 安全
【Rust中的所有权系统深入解析】A Deep Dive into Rust‘s Ownership System
【Rust中的所有权系统深入解析】A Deep Dive into Rust‘s Ownership System
98 0
|
6月前
|
Rust 安全 编译器
深入Rust的所有权系统:理解变量的所有权
本文详细探讨了Rust编程语言中所有权系统的核心概念,包括变量的所有权、生命周期、借用规则和内存安全。通过理解这些概念,我们能够编写出更加高效、安全和可维护的Rust代码。
|
6月前
|
Rust 编译器
【Rust】——函数(所有权)以及借用或引用
【Rust】——函数(所有权)以及借用或引用
|
6月前
|
存储 缓存 Rust
【Rust】——所有权:Stack(栈内存)vs Heap(堆内存)(重点)
【Rust】——所有权:Stack(栈内存)vs Heap(堆内存)(重点)
|
6月前
|
存储 Rust 安全
Rust核心功能之一(所有权)
Rust核心功能之一(所有权)