--- title: Rust date: 2023-09-15 09:25:54 tags: --- # Rust 教程 ## 第一个 Rust 程序 Rust语言代码文件后缀名为`.rs`,如helloworld.rs。 ```rust fn main() { println!("Hello World!"); } ``` 使用`rustc`命令编译helloworld.rs文件: ```shell rustc helloworld.rs # 编译 helloworld.rs 文件 ``` 编译后会生成helloworld可执行文件: ```shell ./helloworld # 执行 helloworld Hello World! ``` # Rust 环境搭建 ## 安装 Rust 编译工具 Rust 编译工具从链接 [安装 Rust - Rust 程序设计语言 (rust-lang.org)](https://www.rust-lang.org/zh-CN/tools/install) 中下载的Rustup安装。下载好的Rustup在Windows 上是一个可执行程序 rustup-init.exe。(在其他平台上应该是`rustup-init.sh`)。 现在执行 rustup-init 文件: ![image-20230915102448742](https://markdownhexo.oss-cn-hangzhou.aliyuncs.com/img/image-20230915102448742.png) ![image-20230915135358199](https://markdownhexo.oss-cn-hangzhou.aliyuncs.com/img/image-20230915135358199.png) 上图显示的是一个命令行安装向导。 **如果你已经安装MSVC(推荐),那么安装过程会非常的简单,输入 1 并回车,直接进入第二步。** 如果你安装的是MinGW,那么你需要输入 2(自定义安装),然后系统会询问你 Default host triple?,请将上图中 **default host triple**的"msvc"改为"gnu"再输入安装程序: ![img](https://www.runoob.com/wp-content/uploads/2020/04/rust-env2.png) 其他属性都默认。 设置完所有选项,会回到安装向导界面(第一张图),这时我们输入 1 并回车即可。 ![img](https://www.runoob.com/wp-content/uploads/2020/04/rust-env3.png) 进行到这一步就完成了Rust的安装,可以通过以下命令测试: ```shell rustc -V # 注意大写的 V ``` ![img](https://www.runoob.com/wp-content/uploads/2020/04/rust-env4.png) 如果以上两个命令能够输出你安装的版本号,就是安装成功了。 ## 搭建 Visual Studio Code 开发环境 安装`rust-analyzer`和`Native Debug`两个扩展。 ![img](https://www.runoob.com/wp-content/uploads/2020/04/49033261-B1B8-4D70-8090-53DC45A8727E.jpeg) ![img](https://www.runoob.com/wp-content/uploads/2020/04/rust-env8.png) 重新启动 VsCode,Rust 的开发环境就搭建好了。 现在新建一个文件夹,如 RustLearn。 在VsCode中打开新建的文件夹。 打开文件夹后,新建终端。 输入以下命令: ```shell cargo new greeting ``` 当前文件夹下会构建一个名叫 greeting 的 Rust 的工程目录。 在终端里输入以下三个命令: ```shell cd ./greeting cargo build cargo run ``` 系统在创建工程时会生成一个Hello World源程序main.rs,这时会被编译运行: # Cargo 教程 ## Cargo 是什么 Cargo 是 Rust 的构建系统和包管理器。 Rust 开发者 常用 Cargo 来管理 Rust 工程和获取工程所依赖的库。在上个教程中我们曾使用 cargo new greeting 命令创建一个名为 greeting 的工程,Cargo 新建了一个名为 greeting 的文件夹并在里面部署了一个 Rust 工程最典型的文件结构。这个 greeting 文件夹就是工程本身。 ## Cargo 功能 Cargo 除了创建工程以外还具备构建(build)工程、运行(run)工程等一系列功能,构建和运行分别对应以下命令: ```shell cargo build cargo run ``` Cargo 还具有获取包、打包、高级构建等功能,详细使用方法参见 Cargo 命令。 ```shell cargo clippy # 类似ESLint,lint工具检查代码可以优化的地方 cargo fmt # 类似go fmt,代码格式化 cargo tree # 查看第三方库的版本和依赖关系 cargo bench # 运行benchmark(基准测试,性能测试) cargo udeps # (第三方)检查项目中未使用的依赖 # 另外cargo build/run --release 使用release编译会比默认的debug编译性能提升10倍以上,但是 release 缺点是编译速度较慢,而且不会显示 panic backtrace 的具体行号 ``` ## 在 VsCode 中配置 Rust 工程 Cargo 是一个不错的构建工具,如果使VsCode 与它相配合那么 VsCode 将会是一个十分便捷的开发环境。 在上一章中我们建立了 greeting 工程,现在我们用 VsCode 打开 greeting 文件夹**(注意不是 RustLeanrning)**。 打开 greeting 之后,在里面新建一个新的文件夹`.vscode` # Rust 输出到命令行 在正式学习 Rust 语言以前,我们需要先学会怎样输出一段文字到命令行,这几乎是学习每一门语言之前必备的技能,因为输出到命令行几乎是语言学习阶段程序表达结果的唯一方式。 在之前的 Hello, World 程序中大概已经告诉了大家输出字符串的方式,但并不全面,大家可能很疑惑为什么 println!( "Hello World") 中的 println 后面还有一个 `!` 符号,难道 Rust 函数之后都要加一个感叹号?显然并不是这样。println 不是一个函数,而是一个宏规则。这里不需要更深刻的挖掘宏规则是什么,后面的章节中会专门介绍,并不影响接下来的一段学习。 Rust 输出文字的方式主要有两种:`println!()` 和 `print!()`。这两个"函数"都是向命令行输出字符串的方法,区别仅在于前者会在输出的最后附加输出一个换行符。当用这两个"函数"输出信息的时候,第一个参数是格式字符串,后面是一串可变参数,对应着格式字符串中的"占位符",这一点与 C 语言中的 printf 函数很相似。但是,Rust 中格式字符串中的占位符不是 **"% + 字母"** 的形式,而是一对 **{}**。 `printlna.rs`文件 ```rust fn main() { let a = 12; println!("a is {}", a); } ``` 使用`rustc`命令编译`printlna.rs`文件: ```rust rustc printlna.rs # 编译 printlna.rs 文件 ``` 编译后会生成 `printlna`可执行文件: ```shell ./printlna # 执行 printlna ``` 以上程序的输出结果是: ```shell a is 12 ``` 如果我想把 a 输出两遍,那岂不是要写成: ```rust println!("a is {}, a again is {}", a, a); ``` 其实有更好的写法: ```rust println!("a is {0}, a again is {0}", a); ``` 在`{}`之间可以放一个数字,它将把之后的可变参数当做一个数组来访问,下标从0开始。 如果要输出 **{** 或 **}** 怎么办呢?格式字符串通过 **{{** 和 **}}** 分别转义代表 { 和 } 。但是其他常用转义字符与 C 语言里的转义字符一样,都是反斜杠开头的形式。 ```rust fn main() { println!("{{}}"); } ``` 以上程序的输出结果是: ```shell {} ``` # Rust 基础语法 变量,基本类型,函数,注释和控制流,这些几乎是每种编程语言都具有的编程概念。 这些基础概念将存在于每个 Rust 程序中,及早学习它们将使你以最快的速度学习 Rust 的使用。 ## 变量 首先必须说明,Rust 是强类型语言,但具有自动判断变量类型的能力。这很容易让人与弱类型语言产生混淆。 如果要声明变量,需要使用 `let` 关键字。例如: ```rust let a = 123; ``` 只学习过 JavaScript 的开发者对这句话很敏感,只学习过 C 语言的开发者对这句话很不理解。 在这句声明语句之后,以下三行代码都是被禁止的: ```rust a = "abc"; a = 4.56; a = 456; ``` 第一行的错误在于当声明 a 是 123 以后,a 就被确定为整型数字,不能把字符串类型的值赋给它。 第二行的错误在于自动转换数字精度有损失,Rust 语言不允许精度有损失的自动数据类型转换。 第三行的错误在于 a 不是个可变变量。 前两种错误很容易理解,但第三个是什么意思?难道 a 不是个变量吗? 这就牵扯到了 Rust 语言为了高并发安全而做的设计:在语言层面尽量少的让变量的值可以改变。所以 a 的值不可变。但这不意味着 a 不是"变量"(英文中的 variable),官方文档称 a 这种变量为"不可变变量"。 如果我们编写的程序的一部分在假设值永远不会改变的情况下运行,而我们代码的另一部分在改变该值,那么代码的第一部分可能就不会按照设计的意图去运转。由于这种原因造成的错误很难在事后找到。这是 Rust 语言设计这种机制的原因。 当然,使变量变得"可变"(mutable)只需一个 `mut`关键字。 ```rust let mut a = 123; a = 456; ``` 这个程序是正确的。 ## 常量与不可变变量的区别 既然不可变变量是不可变的,那不就是常量吗?为什么叫变量? 变量和常量还是有区别的。在 Rust 中,以下程序是合法的: ```rust let a = 123; // 可以编译,但可能有警告,因为该变量没有被使用 let a = 456; ```