当前位置: 首页 > news >正文

rust学习笔记

  • 参考资料:https://doc.rust-lang.org/book/ch01-02-hello-world.html

一、 编译与运行

在 Rust 中,编译和运行代码的常用命令是使用 cargo,这是 Rust 的包管理和构建工具。以下是使用 cargorustc(Rust 编译器)的具体命令:

1. 使用 cargo 工具

cargo 是 Rust 的推荐工具,因为它可以处理依赖管理、构建、测试等多个功能。

  • 编译和运行项目:

    cargo run
    

    该命令将编译项目并运行可执行文件。cargo run 是一个方便的命令,适用于开发过程中快速测试代码。

  • 仅编译项目:

    cargo build
    

    该命令只会编译项目,而不运行。编译后的可执行文件通常位于 target/debug/ 目录下。

  • 编译发布版本:

    cargo build --release
    

    使用 --release 选项来编译一个优化的发布版本。编译后的可执行文件通常位于 target/release/ 目录下。

2. 使用 rustc 命令

如果你想直接使用 Rust 编译器 rustc,而不使用 cargo,可以使用以下命令:

  • 编译文件:

    rustc main.rs
    

    这将使用 rustc 编译器直接编译 main.rs 文件,并生成一个名为 main(Windows 下为 main.exe)的可执行文件。

  • 运行可执行文件:

    编译完成后,运行生成的可执行文件:

    ./main    # 在 Unix 或 Linux 系统上
    main.exe  # 在 Windows 系统上
    

二、如何显式的处理数字类型的溢出

相关教程章节:https://doc.rust-lang.org/book/ch03-02-data-types.html

Rust 提供了多种方法来处理整数溢出,这些方法可以帮助你根据需要选择适当的策略来应对可能的溢出。让我们逐个分析这些方法,并举例说明它们的用法。

1. wrapping_* 方法

  • 描述:当发生溢出时,wrapping_* 方法会绕回到类型的最小值(或最大值),即在所有模式下(包括 debugrelease 模式)进行“环绕”(wrap around)处理。
  • 使用场景:适用于希望溢出后从类型的边界“环绕”回来的情况,比如在循环计数时。

示例:

fn main() {let max = u8::MAX; // u8 的最大值是 255let wrapped = max.wrapping_add(1); // 255 + 1 应该是 256,但会“环绕”回 0println!("Wrapped value: {}", wrapped); // 输出: Wrapped value: 0
}
  • 解释:u8 类型的最大值是 255。wrapping_add(1) 将会“环绕”回 0,因为 u8 只能存储 0 到 255 之间的值。

2. checked_* 方法

  • 描述checked_* 方法在发生溢出时返回 None,否则返回 Some(value)
  • 使用场景:适用于需要检测溢出并希望在溢出时采取一些特定措施的情况(例如返回一个 None 值表示错误)。

示例

fn main() {let max = u8::MAX; // u8 的最大值是 255let checked = max.checked_add(1); // 255 + 1 会溢出match checked {Some(value) => println!("Checked value: {}", value),None => println!("Overflow occurred!"), // 输出: Overflow occurred!}
}
  • 解释:checked_add(1) 会检测到溢出,因为 255 + 1 超出了 u8 类型的范围,因此返回 None

3. overflowing_* 方法

  • 描述overflowing_* 方法返回一个元组 (value, bool),其中 value 是操作结果,bool 表示是否发生了溢出(true 表示发生溢出)。
  • 使用场景:适用于需要知道溢出发生与否,同时还需要获取操作结果的情况。

示例

fn main() {let max = u8::MAX; // u8 的最大值是 255let (overflowed_value, did_overflow) = max.overflowing_add(1); // 255 + 1 会溢出println!("Overflowing value: {}", overflowed_value); // 输出: Overflowing value: 0println!("Did overflow: {}", did_overflow); // 输出: Did overflow: true
}
  • 解释:overflowing_add(1) 返回一个元组,其中第一个值是溢出后的结果(即环绕后的值 0),第二个值是一个布尔值,表示是否发生了溢出(true 表示发生了溢出)。

4. saturating_* 方法

  • 描述saturating_* 方法在溢出时返回类型的最小值或最大值,而不是产生环绕效果。
  • 使用场景:适用于希望结果在类型的范围内“饱和”(即限制在最大值或最小值)而不发生环绕的情况,比如计算结果不能超过一个特定的上限或下限。

示例

fn main() {let max = u8::MAX; // u8 的最大值是 255let saturated = max.saturating_add(1); // 255 + 1 会溢出println!("Saturating value: {}", saturated); // 输出: Saturating value: 255
}
  • 解释:saturating_add(1) 在发生溢出时不会绕回到 0,而是返回 u8 类型的最大值(255),这是“饱和”效果的表现。

总结

  • wrapping_* 方法:当发生溢出时,结果“环绕”回类型的边界值。
  • checked_* 方法:当发生溢出时,返回 None,否则返回 Some(value)
  • overflowing_* 方法:返回一个元组 (value, bool),表示结果和是否发生溢出。
  • saturating_* 方法:当发生溢出时,返回类型的最小值或最大值(不发生环绕)。

三、控制台打印中{}{:?}的区别

在 Rust 中,{:?}{} 都是格式化占位符,但它们的用途和作用有所不同。

{:?}{} 的区别

  1. {:?}:表示调试格式化(debug formatting)。它用于打印那些实现了 Debug trait 的类型的值。它的输出通常更详细,适用于开发和调试用途。使用 {:?} 时,Rust 不仅会打印变量的值,还会尽可能地显示它们的内部结构。

  2. {}:表示显示格式化(display formatting)。它用于打印那些实现了 Display trait 的类型的值。Display trait 更像是用户友好的输出格式,而不是用于调试的信息。并不是所有类型都实现了 Display trait,例如,常见的 Rust 标准类型(如 OptionResult)默认没有实现 Display

为什么用 {:?} 而不是 {}

在 Rust 中,大多数基本数据类型(如 booli32f64 等)都同时实现了 DebugDisplay trait,因此你可以使用 {:?}{} 来打印它们的值。但是,使用 {:?} 更通用,它适用于更广泛的类型。

例子:

println!("a = {:?}, b = {:?}", a, b);

这是用来打印布尔值 ab。虽然 bool 类型同时实现了 DebugDisplay,但一般情况下:

  • 使用 {:?} 是一种好习惯,因为它可以打印更复杂的数据结构,例如元组、数组、向量、枚举等。在这些情况下,{:?} 可以打印更多细节而无需更改代码。

  • {:?} 更通用,它能确保你在需要打印复杂数据结构时不出错,而 {} 只能用于实现了 Display 的类型。

示例:{:?} vs {}

让我们看一个例子来更好地理解这两个占位符的区别。

使用 {:?} 调试格式化
fn main() {let tuple = (42, "hello", vec![1, 2, 3]);// 使用调试格式化打印println!("{:?}", tuple);
}

输出:

(42, "hello", [1, 2, 3])
  • 这里使用 {:?} 成功打印了元组的所有内容,包含整数、字符串和向量的详细信息。
使用 {} 显示格式化
fn main() {let tuple = (42, "hello", vec![1, 2, 3]);// 使用显示格式化打印println!("{}", tuple); // 编译错误
}

输出:

error[E0277]: `({integer}, &str, std::vec::Vec<{integer}>)` doesn't implement `std::fmt::Display`
  • 上述代码会产生编译错误,因为元组 (42, "hello", vec![1, 2, 3]) 没有实现 Display trait,因此不能使用 {} 来打印它。

总结

  • {:?}:用于调试格式化,适用于所有实现了 Debug trait 的类型。更通用,更适合打印复杂的数据结构和调试输出。
  • {}:用于显示格式化,适用于实现了 Display trait 的类型。输出更简洁,但不适用于所有类型。

四、BACKTRACE

在 Rust 中,当程序发生 panic(恐慌)时,会打印一个错误消息,描述导致 panic 的原因。

note: run with RUST_BACKTRACE=1 environment variable to display a backtrace 的含义

这条提示信息的意思是:如果你希望看到导致 panic 的完整调用栈(backtrace),可以运行程序时设置环境变量 RUST_BACKTRACE=1

什么是 Backtrace?

  • Backtrace 是一种调试信息,它显示了程序在发生 panic 时的调用堆栈(函数调用的路径)。
  • 通过查看 backtrace,可以了解程序是如何到达 panic 点的,这对调试程序非常有用。
  • 在 Rust 中,默认情况下,当程序发生 panic 时,Rust 只会显示一个简短的错误信息(如你看到的那样),不会显示完整的 backtrace。

如何启用 Backtrace?

要启用 backtrace,可以在运行程序时设置 RUST_BACKTRACE 环境变量为 1。这样 Rust 会在 panic 发生时打印出更详细的调用堆栈。

示例:在不同平台上启用 Backtrace
  • Linux/macOS

    在终端中运行以下命令:

    RUST_BACKTRACE=1 cargo run
    

    或者如果你直接使用编译后的可执行文件,可以这样运行:

    RUST_BACKTRACE=1 ./your_program_name
    
  • Windows

    在命令提示符中运行以下命令:

    set RUST_BACKTRACE=1
    cargo run
    

    或者,如果你直接运行可执行文件,可以这样运行:

    set RUST_BACKTRACE=1
    your_program_name.exe
    

启用 Backtrace 后的输出

启用 backtrace 后,运行程序时,你会看到类似以下的输出:

thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:19:19
stack backtrace:0: std::panicking::begin_panic1: core::panicking::panic_bounds_check2: <your_function_name>...8: main9: __libc_start_main10: _start

解释

  • 这些信息显示了程序中发生 panic 的函数调用栈。每一行对应一个函数调用。
  • 通过查看这些信息,你可以追踪导致 panic 的路径,找到出错的代码段并进行修复。

五、解构式赋值

rust教程:https://course.rs/basic/variable.html

这段教程介绍了 Rust 1.59 版本后支持的一种新的赋值方式——解构式赋值。这种方式允许在赋值语句中使用元组、切片和结构体的模式,从而直接给多个变量赋值或更新变量的值。它类似于 let 语句的解构绑定,但不同的是,let 语句用于变量的初次绑定,而解构式赋值用于已经绑定的变量的再赋值。

什么是解构式赋值?

解构式赋值 是一种赋值方法,它允许你使用模式匹配的方式将值“解构”并赋给多个变量。在 Rust 1.59 之前,这种操作只能在 let 语句中使用,而在 Rust 1.59 之后,它被扩展到普通的赋值语句中,使得代码更加简洁和易于理解。

解释代码示例

我们来看一下你的代码示例,并逐步分析每一行:

struct Struct {e: i32
}fn main() {let (a, b, c, d, e);(a, b) = (1, 2);// _ 代表匹配一个值,但是我们不关心具体的值是什么,因此没有使用一个变量名而是使用了 _[c, .., d, _] = [1, 2, 3, 4, 5];Struct { e, .. } = Struct { e: 5 };assert_eq!([1, 2, 1, 4, 5], [a, b, c, d, e]);
}
1. 结构体定义
struct Struct {e: i32
}
  • 定义了一个简单的结构体 Struct,它只有一个字段 e,类型是 i32
2. 解构式赋值的例子
fn main() {let (a, b, c, d, e);
  • 这里用 let 声明了五个变量 a, b, c, d, 和 e,但是没有为它们赋值。
    (a, b) = (1, 2);
  • 解构式赋值:将元组 (1, 2) 中的值解构并分别赋给 ab。结果是 a = 1b = 2
    [c, .., d, _] = [1, 2, 3, 4, 5];
  • 这里我们对数组 [1, 2, 3, 4, 5] 使用了解构赋值。
    • c 取得第一个元素 1
    • .. 表示忽略中间的元素(这里是 [2, 3])。
    • d 取得倒数第二个元素 4
    • _ 匹配最后一个元素 5,但我们不关心它的值,因此使用 _ 忽略掉。
    • 结果是 c = 1d = 4
    Struct { e, .. } = Struct { e: 5 };
  • 对结构体进行解构赋值。
    • Struct { e, .. } 是一个模式,匹配 Struct 结构体类型。
    • .. 表示忽略结构体中的其他字段(如果有的话)。
    • e 取得结构体中 e 字段的值(这里是 5)。
    • 结果是 e = 5
3. 断言
    assert_eq!([1, 2, 1, 4, 5], [a, b, c, d, e]);
  • assert_eq! 宏用于断言两个值相等。
  • 它比较数组 [1, 2, 1, 4, 5] 和变量的值 [a, b, c, d, e] 是否相等。
  • 由于前面的解构式赋值,我们知道 a = 1b = 2c = 1d = 4e = 5,因此断言成功,程序继续执行。

解构式赋值 vs. let 绑定

  • let 绑定:在初次声明变量时使用。let 语句会新建变量,并绑定一个值或解构多个值。

    let (x, y) = (10, 20); // 新建变量 x 和 y,并赋值
    
  • 解构式赋值:在已经声明的变量上使用。解构式赋值仅仅是对已存在变量的再赋值。

    let x;
    x = 5; // 给已声明的变量 x 赋值
    
注意事项
  • 使用 += 等运算符进行赋值时,还不支持解构式赋值。这意味着你不能对解构后的变量直接使用 += 等操作符,例如:

    (x, y) += (1, 2); // 这是不允许的,编译时会报错
    

总结

  • 解构式赋值 是一种灵活的赋值方式,它允许你在赋值语句中使用元组、切片和结构体模式进行解构。
  • 它保持了与 let 语句的使用一致性,但用于已经声明的变量,而不是创建新的变量。
  • 使用这种方式可以简化对多值赋值的操作,使代码更加简洁和易读。

相关文章:

rust学习笔记

参考资料&#xff1a;https://doc.rust-lang.org/book/ch01-02-hello-world.html 一、 编译与运行 在 Rust 中&#xff0c;编译和运行代码的常用命令是使用 cargo&#xff0c;这是 Rust 的包管理和构建工具。以下是使用 cargo 和 rustc&#xff08;Rust 编译器&#xff09;的具…...

【有啥问啥】复习变分下界即证据下界(Evidence Lower Bound, ELBO):原理与应用

复习变分下界即证据下界&#xff08;Evidence Lower Bound, ELBO&#xff09;&#xff1a;原理与应用 变分下界&#xff08;Variational Lower Bound&#xff09;&#xff0c;也称为“证据下界”&#xff08;Evidence Lower Bound, ELBO&#xff09;&#xff0c;是概率模型中的…...

Linux shell编程学习笔记78:cpio命令——文件和目录归档工具(上)

0 前言 在Linux系统中&#xff0c;除了tar命令&#xff0c;我们还可以使用cpio命令来进行文件和目录的归档。 1 cpio命令的功能&#xff0c;帮助信息&#xff0c;格式&#xff0c;选项和参数说明 1.1 cpio命令的功能 cpio 名字来自 "copy in, copy out"&#xf…...

为什么在 JSON 序列化中不使用 transient

有些小伙伴发现了&#xff0c;明明在返回的实体类中指定了属性为transient。为什么前端得到的返回json中还是有这个属性的值&#xff1f; 类&#xff1a; private String name; private transient String password;返回结果&#xff1a; { name:"刘大大", password:…...

K8S - Volume - NFS 卷的简介和使用

在之前的文章里已经介绍了 K8S 中两个简单卷类型 hostpath 和 emptydir k8s - Volume 简介和HostPath的使用 K8S - Emptydir - 取代ELK 使用fluentd 构建logging saidcar 但是这两种卷都有同1个限制&#xff0c; 就是依赖于 k8s nodes的空间 如果某个service pod中需要的vol…...

IO模型---BIO、NIO、IO多路复用、AIO详解

本篇将想给详细解释一下什么是BIO、NIO、IO多路复用以及AIO~ 同步的阻塞(BIO)和非阻塞(NIO)的区别 BIO&#xff1a;线程发来IO请求后&#xff0c;一直阻塞着IO线程&#xff0c;需要缓冲区这边数据准备好之后&#xff0c;才会进行下一步的操作。 举个&#x1f330;&#xff1…...

蓝桥杯真题——约翰的牛奶

输入样例&#xff1a; 8 9 10 输出样例&#xff1a; 1 2 8 9 10 本题是宽搜的模版题&#xff0c;不论怎么倒牛奶&#xff0c;A,B,C 桶里的牛奶可以看做一个三元点集 我们只要找到A桶是空的&#xff0c;B,C桶中的状态即可 #include <iostream> #include <cstring…...

单机docker-compose部署minio

单机多副本docker-compose部署minio 简单介绍 如果服务器有限可以单机挂载多硬盘实现多副本容错&#xff08;生产不推荐&#xff09; 部署好的文件状态 有两个重要文件 docker-compose.yaml和nginx.conf docker-compose.yaml是docker部署容器的配置信息包括4个minio和1个ng…...

Winform实现弹出定时框功能

1、程序 private void TimeDialogInitialize(){for(int i1; i<30;i){cbbTimeDialog.Items.Add(i);}}private void cbbTimeDialog_SelectedIndexChanged(object sender, EventArgs e){foreach(int i in cbbTimeDialog.Items){if(cbbTimeDialog.SelectedItem!null &&…...

【机器学习(四)】分类和回归任务-梯度提升决策树(GBDT)-Sentosa_DSML社区版

文章目录 一、算法概念一、算法原理&#xff08;一&#xff09; GBDT 及负梯度拟合原理&#xff08;二&#xff09; GBDT 回归和分类1、GBDT回归1、GBDT分类二元分类多元分类 &#xff08;三&#xff09;损失函数1、回归问题的损失函数2. 分类问题的损失函数&#xff1a; 三、G…...

Mini-Omni 语言模型在流式传输中边思考边听说应用

引入简介 Mini-Omni 是一个开源的多模态大语言模型,能够在思考的同时进行听觉和语言交流。它具有实时端到端语音输入和流媒体音频输出的对话能力。 语言模型的最新进展取得了显著突破。GPT-4o 作为一个新的里程碑,实现了与人类的实时对话,展示了接近人类的自然流畅度。为了…...

vue devtools的使用

vue devtools的使用 Vue Devtools 是一个强大的浏览器扩展,旨在帮助你调试和开发 Vue.js 应用。它支持 Chrome 和 Firefox 浏览器,并提供了一些工具和功能,可以让你更轻松地查看和调试 Vue 应用的状态和行为。以下是如何安装和使用 Vue Devtools 的详细指南。 安装 Vue De…...

无人机培训:无人机维护保养技术详解

随着无人机技术的飞速发展&#xff0c;其在航拍、农业、救援、环境监测等领域的应用日益广泛。然而&#xff0c;要确保无人机安全、高效地执行任务&#xff0c;定期的维护保养至关重要。本文将深入解析无人机维护保养的核心技术&#xff0c;涵盖基础构造理解、清洁与防尘、电机…...

Mac 创建 Python 虚拟环境

在 macOS 上&#xff0c;您可以使用以下步骤使用 virtualenv 创建虚拟环境&#xff1a; 首先&#xff0c;确保您已经安装了 Python 和 virtualenv。您可以在终端中运行以下命令来检查它们是否已安装&#xff1a; python --version virtualenv --version如果这些命令没有找到&am…...

安卓玩机工具-----无需root权限 卸载 禁用 删除当前机型app应用 ADB玩机工具

ADB玩机工具 ADB AppControl是很实用的安卓手机应用管理工具&#xff0c;无需root权限&#xff0c;通过usb连接电脑后&#xff0c;可以很方便的进行应用程序安装与卸载&#xff0c;还支持提取手机应用apk文件到电脑上&#xff0c;此外还有手机系统垃圾清理、上传文件等…...

中国科技统计年鉴1991-2020年

&#xff08;数据收集&#xff09;中国科技统计年鉴1991-2020年.Excel格式资源-CSDN文库https://download.csdn.net/download/2401_84585615/89475658 《中国科技统计年鉴》是由国家统计局社会科技和文化产业统计司与科学技术部战略规划司共同编辑的官方统计资料书&#xff0c…...

OpenAI / GPT-4o:Python 返回结构化 / JSON 输出

在调用 OpenAI&#xff08;比如&#xff1a;GPT-4o&#xff09;接口时&#xff0c;希望返回的结果是能够在后续任务中自动化处理的结构化 / JSON 输出。GPT 版本&#xff1a;gpt-4o-2024-08-06&#xff0c;提供了这样的功能。 目标&#xff1a;从非结构化输入到结构化数据&…...

通信工程学习:什么是EDFA掺铒光纤放大器

EDFA&#xff1a;掺铒光纤放大器 EDFA&#xff0c;即掺铒光纤放大器&#xff08;Erbium-Doped Fiber Amplifier&#xff09;&#xff0c;是一种在光纤通信中广泛使用的光放大器件。以下是对EDFA的详细解释&#xff1a; 一、定义与基本原理 EDFA是在石英光纤中掺入少量的稀土元…...

机器学习与深度学习的区别

随着人工智能技术的迅猛发展&#xff0c;机器学习&#xff08;Machine Learning, ML&#xff09;和深度学习&#xff08;Deep Learning, DL&#xff09;这两个术语越来越频繁地出现在人们的视野中。尽管它们之间有着紧密的联系&#xff0c;但实际上二者存在显著的区别。本文旨在…...

标准库标头 <barrier>(C++20)学习

此头文件是线程支持库的一部分。 类模板 std::barrier 提供一种线程协调机制&#xff0c;阻塞已知大小的线程组直至该组中的所有线程到达该屏障。不同于 std::latch&#xff0c;屏障是可重用的&#xff1a;一旦到达的线程组被解除阻塞&#xff0c;即可重用同一屏障。与 std::l…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...