【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 所有权的几个核心特点吧:

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

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

相关文章
|
18天前
|
存储 Rust
【Rust】——所有权规则、内存分配
【Rust】——所有权规则、内存分配
31 0
|
18天前
|
存储 Rust 安全
Rust 笔记:Rust 语言中的 所有权 与 生命周期
Rust 笔记:Rust 语言中的 所有权 与 生命周期
140 0
|
18天前
|
Rust 算法 安全
【Rust中的所有权系统深入解析】A Deep Dive into Rust‘s Ownership System
【Rust中的所有权系统深入解析】A Deep Dive into Rust‘s Ownership System
38 0
|
18天前
|
Rust 编译器
【Rust】——函数(所有权)以及借用或引用
【Rust】——函数(所有权)以及借用或引用
24 0
|
18天前
|
存储 缓存 Rust
【Rust】——所有权:Stack(栈内存)vs Heap(堆内存)(重点)
【Rust】——所有权:Stack(栈内存)vs Heap(堆内存)(重点)
28 0
|
18天前
|
Rust 安全 编译器
深入Rust的所有权系统:理解变量的所有权
本文详细探讨了Rust编程语言中所有权系统的核心概念,包括变量的所有权、生命周期、借用规则和内存安全。通过理解这些概念,我们能够编写出更加高效、安全和可维护的Rust代码。
|
18天前
|
存储 Rust 安全
Rust核心功能之一(所有权)
Rust核心功能之一(所有权)
|
7月前
|
Rust 安全 编译器
Rust 基础入门 —— 2.3.所有权和借用 (二)
同一时刻,你只能拥有要么一个可变引用, 要么任意多个不可变引用 引用必须总是有效的 贴一个体验不错的学习链接恰饭:学习链接
47 0
|
7月前
|
Rust 安全 算法
Rust 基础入门 ——所有权 引言 :垃圾自动回收机制的缺陷。
能有这些问题的部分发生场景: 游戏开发:在游戏开发中,需要保持稳定的帧率和低延迟,以提供流畅的游戏体验。如果GC频繁触发或停顿时间过长,会导致游戏卡顿或掉帧,影响游戏的流畅度和响应性能。
56 0
|
7月前
|
存储 Rust 安全
Rust 基础入门 —— 2.3.所有权和借用
写在前面的序言 因为我们这里实际讲述的内容是关于 内存安全的,所以我们最好先复习一下内存的知识。
28 0