# Rust 入门
## 目标
1. 能够搭建和配置Rust 开发环境
2. 掌握Rust 基本语法
3. 能写简单的Rust命令行程序
4. 能够完成编译,链接过程
5. 能够执行单元测试
## Rust 开发环境
参考:<https://hackmd.io/@zenas/rust-app-settings>
需要注意的是,我们需要支持iOS 32位架构,所以需要安装 `1.41.0` 版本,更新的版本已经不支持32位架构了。
## Rust 基本语法
### 变量申明
#### 不变 & 可变
作为一门现代编程语言,`Rust` 支持变量不变性,同时也提供了可变量的便利。
1. 使用 `let` 关键字声明一个不变量
`let x = 42;`
2. 使用 `let mut` 声明一个可变量
```rust=
let mut x = 42;
x = 77; // 可变,可重新赋值
```
#### Shadowing
为了减轻变量命名的烦恼,`Rust` 提供了 `shadowing` 能力,可以重复使用同一个变量名:
```rust=
let x = 1; // 初始值
let x = to_string(x); // x is shadowing
```
#### 类型推导
`Rust` 提供了强大的类型推导能力,可以自动推导出变量的类型:
```rust=
let x = 1; // x is i32
let x: i32 = 1; // with type
```
对于集合类型,甚至可以在填入第一个元素时,推导出类型:
```rust=
let mut x = vec![]; // dont'know the type
x.push(1); // the type is Vec<i32>
```
类型推导是一把双刃剑,好的一面是带来更简洁的代码,同时保证了类型安全;坏的一面是,人类在阅读代码时必须对推导规则烂熟于心,否则难以理解其类型。
但是 Intellij IDE会帮我们提示出推导的类型,可以规避上述负面效果。

### 数据类型
#### 基本数据类型
1. 整数
| Length | Signed | Unsigned |
| ------- | ------- | -------- |
| 8-bit | `i8` | `u8` |
| 16-bit | `i16` | `u16` |
| 32-bit | `i32` | `u32` |
| 64-bit | `i64` | `u64` |
| 128-bit | `i128` | `u128` |
| arch | `isize` | `usize` |
> copy from <https://doc.rust-lang.org/book/ch03-02-data-types.html>
字面量表示:
- 十进制 Decimal: 12_345
- 十六进制 Hex: 0xFF
- 八进制 Octal: 0o77
- 二进制 Binary: 0b1111_0001
- 字节 Byte(u8): b'A'
2. 浮点数
- f32 32位单精度
- f64 64位双精度
3. 数字运算:`+` `-` `*` `/` `%`
4. 布尔值(bool): `true` `false`
5. 字符类型(char): 'x', 'y'
6. unit ()
#### 复合数据类型
1. 元祖 Tuple
```rust=
let point = (1, 1);
let x = point.0;
let y = point.1;
```
2. 数组 Array
```rust=
let arr = [1,2,3];
let arr[i32;3] = [0;3];
let arr_0 = arr[0];
```
#### 结构体Struct
结构体用于定义关联数据,类似于Java里的`Class`。
1. 定义结构
Rust 支持三种结构体
- 没有字段名称的Tuple元组结构体
- 带有字段名称的结构体
- 不带任何字段的结构体(unit)
```rust=
struct Tpl(i32, i32, i32);
struct Name {
first_name: String,
last_name: String,
middle_name: String,
}
struct Phantom;
```
2. 添加方法
与 Java Class 不同,结构体内只能定义数据,不能定义方法,如果需要定义方法, 则需要使用 `impl` 关键字:
```rust=
struct MemberId(String);
struct Payer {
member_id: MemberId,
}
struct Payee {
member_id: MemberId,
}
impl Payer {
// 添加实例方法
fn pay(&self, amount: Amount, payee: Payee) {
todo!();
}
// 添加静态方法
fn new(member_id: String) -> Self {
return Payer {
member_id: MemberId(member_id)
}
}
}
```
3. 创建实例
- 创建元组类型的struct
- 创建带名称的struct
4. 调用方法
对于静态方法,使用 `::` 操作符:
```rust=
let payer = Payer::new(String::from("12345"));
```
对于实例方法,使用 `.` 操作符:
```rust=
let amount = Amount(100);
let payee = Payee {
member_id: MemberId(String::from("56789"))
};
// 调用pay方法
payer.pay(amount, payee);
```
#### 枚举Enum
Rust 提供了`enum`来支持`sum` 类型的抽象
- 简单枚举
```rust=
enum FeatureSwitch {
On,
Off,
}
```
- 带变量的枚举
支持类似于Struct的匿名元组,或者带名称。
```rust=
enum BotCommand {
Standby,
MoveForward(u32),
Bark {
times: u32,
pitch: Pitch
}
}
```
### 流程控制
#### if 流程控制
`if` 在 `Rust` 里,既可以作为Statement(语句)使用,也可以作为Expression(表达式)使用。和其他语言一样,`if` 基本上有一下三种情形:
```rust=
// 只有一个 if
if x > 0 {
}
// if - else
if x > 0 {
} else {
}
// if -else if -else
if x > 10 {
} else if x > 5 {
} else {
}
```
> if 后面的条件表达式,不需要使用括号
作为表达式使用的例子如下:
```rust=
let level = if score > 90 {
"A"
} else if score > 80 {
"B"
} else if score > 60 {
"C"
} else if score > 50 {
"D"
} else {
"E"
}
```
## Hello,Rust World
### 创建命令行程序项目
我们一般使用`cargo`工具来创建项目:
```bash=
cargo new --bin hello_rust
```
完成后, `cargo` 为我们创建了项目的描述文件`Cargo.toml`, 以及可执行文件的入口程序 `src/main.rs`:

可以看出,Rust 程序的入口其他语言一样,都是`main`函数。
我们需要定义一个`lang`不变量,值为`Rust`,并在控制台输出 `Hello, Rust world!`.
```rust=
fn main() {
let lang = String::from("Rust");
println!("Hello,{} world!", lang);
}
```
### 构建
```bash=
cargo build
```
完成构建后,可以在`target`目录下找到相应的可执行程序。
### 单元测试
只需要在测试用例函数上添加属性标注,就可以使用`cargo`进行单元测试:
```rust=
#[test]
fn test_hello_count() {
let hello = String::from("hello");
println!("test length of {}", hello);
assert_eq!(5, hello.len());
}
```
执行 `cargo test` 即可进行单元测试。
需要注意的是,`cargo test` 默认不会输出打印到控制台的信息,可以增加`--nocapture`或者`--show-output`参数强制输出。
> 所有 cargo 子命令都可以使用 `cargo help <sub-command>`获得帮助信息.