CherieLi Student

rust编程

2023-05-16
CherieLi

  • content

Rust 中最大的思维转换就是变量的所有权和生命周期,这是几乎所有编程语言都未曾涉及的领域。
build.rs 编译文件,包含main函数

fn main()
  let include_dirs = 

内存(堆,栈)

编程语言

C 开发者,难点是类型系统和泛型编程; C++ 开发者,难点主要在类型系统;
Python/Ruby/JavaScript 开发者,难点在并发处理、类型系统及泛型编程;
Java 开发者,难点在异步处理和并发安全的理解上;
Swift 开发者,几乎没有额外的难点,深入理解 Rust 异步处理即可。

在编译时,一切无法确定大小或者大小可以改变的数据,都无法安全地放在栈上,最好放在堆上。
那为什么在实际工作中,我们又要避免把大量的数据分配在栈上呢?
这主要是考虑到调用栈的大小,避免栈溢出(stack overflow)
一旦当前程序的调用栈超出了系统允许的最大栈空间,无法创建新的帧,来运行下一个要执行的函数,就会发生栈溢出,这时程序会被系统终止,产生崩溃信息。

当我们需要动态大小的内存时,只能使用堆,比如可变长度的数组、列表、哈希表、字典,它们都分配在堆上。

如果手工管理堆内存的话,堆上内存分配后忘记释放,就会造成内存泄漏。一旦有内存泄漏,程序运行得越久,就越吃内存,最终会因为占满内存而被操作系统终止运行。
如果堆上内存被多个线程的调用栈引用,该内存的改动要特别小心,需要加锁以独占访问,来避免潜在的问题。比如说,一个线程在遍历列表,而另一个线程在释放列表中的某一项,就可能访问野指针,导致堆越界(heap out of bounds)。而堆越界是第一大内存安全问题。
如果堆上内存被释放,但栈上指向堆上内存的相应指针没有被清空,就有可能发生使用已释放内存(use after free)的情况,程序轻则崩溃,重则隐含安全隐患。根据微软安全反应中心(MSRC)的研究,这是第二大内存安全问题。

小结

1.对于存入栈上的值,它的大小在编译期就需要确定。栈上存储的变量生命周期在当前调用栈的作用域内,无法跨调用栈引用。
2.堆可以存入大小未知或者动态伸缩的数据类型。堆上存储的变量,其生命周期从分配后开始,一直到释放时才结束,因此堆上的变量允许在多个调用栈之间引用。
一句话对比总结就是:栈上存放的数据是静态的,固定大小,固定生命周期;堆上存放的数据是动态的,不固定大小,不固定生命周期。

数据(值,类型,指针,引用)

类型是对值的区分,它包含了值在内存中的长度、对齐以及值可以进行的操作等信息。
值是无法脱离具体的类型讨论的。
所有原生类型的大小都是固定的,因此它们可以被分配到栈上。

类型分为原生类型,组合类型。其中组合类型分为结构体类型(struct)和标签联合类型(union)。

指针和引用是原生类型,它们可以分配在栈上。

代码(函数,方法,闭包,接口,虚表)

函数是编程语言的基本要素,它是对完成某个功能的一组相关语句和表达式的封装。
在面向对象的编程语言中,在类或者对象中定义的函数,被称为方法(method)。
闭包是将函数,或者说代码和其环境一起存储的一种数据结构。闭包引用的上下文中的自由变量,会被捕获到闭包的结构中,成为闭包类型的一部分。

作为一个抽象层,接口将使用方和实现方隔离开来,使两者不直接有依赖关系,大大提高了复用性和扩展性。
在生成引用的时候,除了指向数据本身外,还需要指向一张涵盖了这个接口所支持方法的列表。这个列表,就是虚表(virtual table)。 由于虚表记录了数据能够执行的接口,所以在运行期,我们想对一个接口有不同实现,可以根据上下文动态分派。

运行方式(并发,并行,同步,异步)

并发(concurrency)与并行(parallel)

并发是一种能力,而并行是一种手段。
并发是同时与多件事情打交道的能力,比如系统可以在任务 1 做到一定程度后,保存该任务的上下文,挂起并切换到任务 2,然后过段时间再切换回任务 1。
并行是同时处理多件事情的手段。也就是说,任务 1 和任务 2 可以在同一个时间片下工作,无需上下文切换。

同步与异步

异步是指一个任务开始执行后,与它没有因果关系的其它任务可以正常执行,不必等待前一个任务结束。
一般而言,async 定义了一个可以并发执行的任务,而 await 则触发这个任务并发执行。 async/await是Promise的封装,一般用状态机来实现。

编程范式(泛型编程)

数据结构的泛型

安装

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

VS插件:
rust-analyzer:它会实时编译和分析你的 Rust 代码,提示代码中的错误,并对类型进行标注。你也可以使用官方的 Rust 插件取代。
rust syntax:为代码提供语法高亮。
crates:帮助你分析当前项目的依赖是否是最新的版本。
better toml:Rust 使用 toml 做项目的配置管理。
better toml 可以帮你语法高亮,并展示 toml 文件中的错误。
rust test lens:可以帮你快速运行某个 Rust 测试。
Tabnine:基于 AI 的自动补全,可以帮助你更快地撰写代码。

编码
cargo new scrape_url 生成一个新项目:scrape_url
入口在 src/main.rs
cargo run 编译运行
cargo test 运行测试用例
cargo build 编译二进制

Rust 的一些基本特点:
Rust 使用名为 cargo 的工具来管理项目。
Rust 的整体语法偏 C/C++ 风格。
Rust 虽然是一门强类型语言,但编译器支持类型推导。
Rust 支持宏编程。
Rust 的变量默认是不可变的,如果要修改变量的值,需要显式地使用 mut 关键字。
除了 let / static / const / fn 等少数语句外,Rust 绝大多数代码都是表达式(expression)。
所以 if / while / for / loop 都会返回一个值,函数最后一个表达式就是函数的返回值,这和函数式编程语言一致。
Rust 支持面向接口编程和泛型编程。
Rust 有非常丰富的数据类型和强大的标准库。
Rust 有非常丰富的控制流程,包括模式匹配(pattern match)。

Rust 的单元测试一般放在和被测代码相同的文件中,使用条件编译 #[cfg(test)] 来确保测试代码只在测试环境下编译。
Rust 支持声明宏(declarative macro)和过程宏(procedure macro),其中过程宏又包含三种方式:
函数宏(function macro),派生宏(derive macro)和属性宏(attribute macro)。
println! 是函数宏,是因为 Rust 是强类型语言,函数的类型需要在编译期敲定,而 println! 接受任意个数的参数,所以只能用宏来表达。

CLI 工具

作为 CLI 解析库,clap 的整体体验和 Python 的 click 非常类似,但比 Golang 的 cobra 要更简单。

bindgen工具
--cargo 安装
cargo install bindgen-cli --version 0.61.0

--源码安装
      编译方法, 需要搭建好rust编译环境
     cd bindgen-cli
     cargo build --release
      编译好的命令在
     ../target/release/bindgen
参考文档:

https://blog.csdn.net/TowerOs/article/details/104088324
https://www.cnblogs.com/Kempff/p/12705455.html
https://doc.rust-lang.org/book/ 官方文档
https://doc.rust-lang.org/nomicon/
https://github.com/RustMagazine/rust_magazine_2021 rust语言开源杂志
https://www.youtube.com/playlist?list=PLlrxD0HtieHjbTjrchBwOVks_sr8EVW1x
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021 在线执行器
toml: https://toml.io/cn/v1.0.0
https://github.com/tyrchen/geektime-rust


上一篇 gtest学习

下一篇 sftp学习

Comments

Content