Rust学习第十六天
Rust学习第十六天Rust 异步编程 async/await在现代编程中,异步编程变得越来越重要,因为它允许程序在等待 I/O 操作(如文件读写、网络通信等)时不被阻塞,从而提高性能和响应性。
异步编程是一种在 Rust 中处理非阻塞操作的方式,允许程序在执行长时间的 I/O 操作时不被阻塞,而是在等待的同时可以执行其他任务。
Rust 提供了多种工具和库来实现异步编程,包括 async 和 await 关键字、futures 和异步运行时(如 tokio、async-std 等),以及其他辅助工具。
Future:Future 是 Rust 中表示异步操作的抽象。它是一个可能还没有完成的计算,将来某个时刻会返回一个值或一个错误。
async/await:async 关键字用于定义一个异步函数,它返回一个 Future。await 关键字用于暂停当前 Future 的执行,直到它完成。
实例
12345678910111213141516171819202122232425262728// 引入所需的依赖库use tokio;use t ...
Rust学习第十五天
Rust学习第十五天Rust智能指针智能指针(Smart pointers)是一种在 Rust 中常见的数据结构,它们提供了额外的功能和安全性保证,以帮助管理内存和数据。
在 Rust 中,智能指针是一种封装了对动态分配内存的所有权和生命周期管理的数据类型。
智能指针通常封装了一个原始指针,并提供了一些额外的功能,比如引用计数、所有权转移、生命周期管理等。
在 Rust 中,标准库提供了几种常见的智能指针类型,例如 Box、Rc、Arc 和 RefCell。
本文主要介绍声明式宏。
智能指针的使用场景:
当需要在堆上分配内存时,使用 Box<T>。
当需要多处共享所有权时,使用 Rc<T> 或 Arc<T>。
当需要内部可变性时,使用 RefCell<T>。
当需要线程安全的共享所有权时,使用 Arc<T>。
当需要互斥访问数据时,使用 Mutex<T>。
当需要读取-写入访问数据时,使用 RwLock<T>。
当需要解决循环引用问题时,使用 Weak<T>。
Box 智能指针Box 是 ...
Rust学习第十四天
Rust学习第十四天Rust宏Rust 宏(Macros)是一种在编译时生成代码的强大工具,它允许你在编写代码时创建自定义语法扩展。
宏(Macro)是一种在代码中进行元编程(Metaprogramming)的技术,它允许在编译时生成代码,宏可以帮助简化代码,提高代码的可读性和可维护性,同时允许开发者在编译时执行一些代码生成的操作。
宏在 Rust 中有两种类型:声明式宏(Declarative Macros)和过程宏(Procedural Macros)。
本文主要介绍声明式宏。
宏的定义在 Rust 中,使用 macro_rules! 关键字来定义声明式宏。
1234567macro_rules! my_macro { // 模式匹配和展开 ($arg:expr) => { // 生成的代码 // 使用 $arg 来代替匹配到的表达式 };}
声明式宏使用 macro_rules! 关键字进行定义,它们被称为 “macro_rules” 宏。这种宏的定义是基于模式匹配的,可以匹配代码的结构 ...
Rust学习第十三天
Rust学习第十三天Rust 并发编程安全高效的处理并发是 Rust 诞生的目的之一,主要解决的是服务器高负载承受能力。
并发(concurrent)的概念是指程序不同的部分独立执行,这与并行(parallel)的概念容易混淆,并行强调的是”同时执行”。
并发往往会造成并行。
本章讲述与并发相关的编程概念和细节。
线程线程(thread)是一个程序中独立运行的一个部分。
线程不同于进程(process)的地方是线程是程序以内的概念,程序往往是在一个进程中执行的。
在有操作系统的环境中进程往往被交替地调度得以执行,线程则在进程以内由程序进行调度。
由于线程并发很有可能出现并行的情况,所以在并行中可能遇到的死锁、延宕错误常出现于含有并发机制的程序。
为了解决这些问题,很多其它语言(如 Java、C#)采用特殊的运行时(runtime)软件来协调资源,但这样无疑极大地降低了程序的执行效率。
C/C++ 语言在操作系统的最底层也支持多线程,且语言本身以及其编译器不具备侦察和避免并行错误的能力,这对于开发者来说压力很大,开发者需要花费大量的精力避免发生错误。
Rust 不依靠运行时环境 ...
Rust学习第十二天
Rust学习第十二天面向对象面向对象的编程语言通常实现了数据的封装与继承并能基于数据调用方法。
Rust 不是面向对象的编程语言,但这些功能都得以实现。
封装封装就是对外显示的策略,在 Rust 中可以通过模块的机制来实现最外层的封装,并且每一个 Rust 文件都可以看作一个模块,模块内的元素可以通过 pub 关键字对外明示。这一点在”组织管理”章节详细叙述过。
“类”往往是面向对象的编程语言中常用到的概念。”类”封装的是数据,是对同一类数据实体以及其处理方法的抽象。在 Rust 中,我们可以使用结构体或枚举类来实现类的功能:
1234567891011121314151617181920pub struct ClassName { pub field: Type,}pub impl ClassName { fn some_method(&self) { // 方法函数体 }}pub enum EnumName { A, B,}pub impl EnumN ...
Rust学习第十一天
Rust学习第十一天Rust集合和字符串集合(Collection)是数据结构中最普遍的数据存放形式,Rust 标准库中提供了丰富的集合类型帮助开发者处理数据结构的操作。
向量向量(Vector)是一个存放多值的单数据结构,该结构将相同类型的值线性的存放在内存中。
向量是线性表,在 Rust 中的表示是 Vec。
向量的使用方式类似于列表(List),我们可以通过这种方式创建指定类型的向量:
12let vector: Vec<i32> = Vec::new(); // 创建类型为 i32 的空向量let vector = vec![1, 2, 4, 8]; // 通过数组创建向量
我们使用线性表常常会用到追加的操作,但是追加和栈的 push 操作本质是一样的,所以向量只有 push 方法来追加单个元素:
1234567fn main() { let mut vector = vec![1, 2, 4, 8]; vector.push(16); vector.push(32); vector.push(64); prin ...
Rust学习第十天
Rust学习第十天1、Rust 文件与 IO接收命令行参数命令行程序是计算机程序最基础的存在形式,几乎所有的操作系统都支持命令行程序并将可视化程序的运行基于命令行机制。
命令行程序必须能够接收来自命令行环境的参数,这些参数往往在一条命令行的命令之后以空格符分隔。
在很多语言中(如 Java 和 C/C++)环境参数是以主函数的参数(常常是一个字符串数组)传递给程序的,但在 Rust 中主函数是个无参函数,环境参数需要开发者通过 std::env 模块取出,过程十分简单:
1234fn main() { let args = std::env::args(); println!("{:?}", args);}
运行结果:
1Args { inner: ["D:\\rust\\greeting\\target\\debug\\greeting.exe"] }
也许你得到的结果比这个要长的多,这很正常,这个结果中 Args 结构体中有一个 inner 数组,只包含唯一 ...
Rust学习第九天
Rust学习第九天1、Rust 生命周期Rust 生命周期机制是与所有权机制同等重要的资源管理机制。
之所以引入这个概念主要是应对复杂类型系统中资源管理的问题。
引用是对待复杂类型时必不可少的机制,毕竟复杂类型的数据不能被处理器轻易地复制和计算。
但引用往往导致极其复杂的资源管理问题,首先认识一下垂悬引用:Rust 生命周期机制是与所有权机制同等重要的资源管理机制。
之所以引入这个概念主要是应对复杂类型系统中资源管理的问题。
引用是对待复杂类型时必不可少的机制,毕竟复杂类型的数据不能被处理器轻易地复制和计算。
但引用往往导致极其复杂的资源管理问题,首先认识一下垂悬引用:
12345678910{ let r; { let x = 5; r = &x; } println!("r: {}", r);}
这段代码是不会通过 Rust 编译器的,原因是 r 所引用的值已经在使用之前被释放。
上图中的绿色范围 ‘a 表示 r 的生命周期,蓝色范围 ‘b ...
Rust学习第八天
Rust学习第八天1、Rust 泛型与特性泛型是一个编程语言不可或缺的机制。
C++ 语言中用”模板”来实现泛型,而 C 语言中没有泛型的机制,这也导致 C 语言难以构建类型复杂的工程。
泛型机制是编程语言用于表达类型抽象的机制,一般用于功能确定、数据类型待定的类,如链表、映射表等。
在函数中定义泛型这是一个对整型数字选择排序的方法:
12345678910111213141516fn max(array: &[i32]) -> i32 { let mut max_index = 0; let mut i = 1; while i < array.len() { if array[i] > array[max_index] { max_index = i; } i += 1; } array[max_index]}fn main() { let a = [2, 4, 6, 3, 1]; ...
Rust学习第七天
Rust学习第七天1、错误处理Rust 有一套独特的处理异常情况的机制,它并不像其它语言中的 try 机制那样简单。
首先,程序中一般会出现两种错误:可恢复错误和不可恢复错误。
可恢复错误的典型案例是文件访问错误,如果访问一个文件失败,有可能是因为它正在被占用,是正常的,我们可以通过等待来解决。
但还有一种错误是由编程中无法解决的逻辑错误导致的,例如访问数组末尾以外的位置。
大多数编程语言不区分这两种错误,并用 Exception (异常)类来表示错误。在 Rust 中没有 Exception。
对于可恢复错误用 Result<T, E> 类来处理,对于不可恢复错误使用 panic! 宏来处理。
不可恢复错误本章以前没有专门介绍 Rust 宏的语法,但已经使用过了 println! 宏,因为这些宏的使用较为简单,所以暂时不需要彻底掌握它,我们可以用同样的方法先学会使用 panic! 宏的使用方法。
1234fn main() { panic!("error occured"); println!("Hello, Rust& ...