「Learn Rust」#0 总章

学习一门新语言之Haskell

前言

Haskell学的差不多了,也没啥事想干了
GZTime之前也跟我推荐过Rust挺好玩的
这几天看一看
一样,没有教程,只是我的笔记而已

Installation

Mac上安装只需要安装rustup即可:

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

然后更新、卸载、检查:

1
2
3
$ rustup update
$ rustup self uninstall
$ rustc --version

Rust代码的后缀名是.rs,通过rustc code.rs来编译出二进制文件code再运行

Cargo

通过rustup安装后自带cargo,可以通过cargo --version检查

通过cargo new project_name来新建一个项目,这时会在当前目录下自动生成下面的目录结构:

1
2
3
4
5
6
project_name
├── .git/
├── .gitignore
├── Cargo.toml
└── src
└── main.rs

cargo会根据输入的项目名称新建一个文件夹,并且默认使用git进行版本控制(可以使用cargo new ... --vcs none取消版本控制)

其中main.rs文件中就是一个Hell World程序。Cargo.toml是这个项目的配置文件:

1
2
3
4
5
6
7
8
[package]
name = "project_name"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

构建、运行、发布

  • 使用cargo build会构建这个项目,并且将可执行文件创建在target/debug/文件夹中
  • 使用cargo run直接构建并运行这个项目
  • 使用cargo check检查项目,但不生产可执行文件、也不输出结果
  • 使用cargo build --release来发布,产生但可执行文件在target/release/文件夹中,不用于直接build,它会进行一些优化来使程序运行地更快

常见编程概念

变量

let语句会创建一个变量,但是默认都是不可变的(immutable)。即一旦使用let创建一个变量并为其赋值,那这个变量将不允许被改动,如果在代码中改动了这个变量,那么将不会通过编译

但是可以再使用let语句来创建一个同名变量:

1
2
let x = 1;
let x = x + 1;

这时,原来的x就被隐藏(shadowing)了(这种方式的前后两个x本质上还是两个变量,它们允许有着不同的数据类型)

在let后面加上mut也可以创建一个可变的变量:

1
2
let mut x = 1;
x = x + 1;

但这时x不能更改数据类型

常量

常量不同于变量,它一定是不可变的。常量通过const关键字创建,而且需要明确指定数据类型(Rust常量命名规范是用全大写):

1
const MAX_POINT: u32 = 100_000;

数据类型

Rust是静态类型语言,编译器需要在编译时得到所有变量的类型,但是也可以自动推测类型。

Rust中的类型分为两种,标量(scalar)和复合(compound)

scalar

整型

长度 有符号 无符号
8-bit i8 u8
16-bit i16 u16
32-bit i32 u32
64-bit i64 u64
128-bit i128 u128
arch isize usize

isizeusize是根据系统而定(32/64)

同时整型的值也可以用不同进制表示(十六进制0x开头,八进制0o开头,二进制0b开头,单字节字符b开头(b’A’)),在数值中间也可以增加_来增强可读性,在数值结尾也可以加上类型后缀来明确类型

浮点型
单精度浮点f32,双精度浮点f64

布尔型
bool,值是小写true/false

字符型
char,四字节(使用unicode)。字符是单引号而字符串是双引号

compound

元组
元素类型可以不同,但是整个元组的类型和各个元素的类型都有关,例如:

1
let tup: (i32, f64, u8) = (500, 6.4, 1);

可以通过.加索引来访问元素:

1
let x = tup.1

列表
不同于Python/Haskell,Rust中的列表的长度也是不可变的,而且列表中的所有元素的类型也必须一致。含有五个i32类型的元素的列表的类型就可以写成[i32; 5]

同时[3; 5]这种写法也等价于[3, 3, 3, 3, 3]

可以通过[index]来访问元素,如lst[1]。但如果索引超出列表元素个数,那么编译将不会报错,但运行时会报错

函数

通过fn关键字来定义函数,参数的类型必须指定,如果有返回值,返回值的类型也要在()后面用-> type指定。返回值可以在函数中途直接return返回,也可以在函数结尾直接写出要返回的值(不加分号,此时是表达式而不是语句),比如:

1
2
3
fn plus_one(x: i32) -> i32 {
x + 1
}

同样,用{}括上的代码块也是一个表达式,它也可以有返回值:

1
2
3
4
5
let x = 5;
let y = {
let x = 3;
x + 1
};

控制流

条件

常规的if语句,比如:

1
2
3
4
5
6
7
if a == 1 {
...;
} else if a == 2 {
...;
} else {
...;
}

不同于Haskell,它可以没有else只有if

if语句也可以用在let上,这时{}中要是一个表达式而不是语句,即不带分号:

1
2
3
4
5
let number = if condition {
5
} else {
6
};

循环

loop
使用loop会将块一直循环直到遇到break,也可以从loop循环返回值,比如:

1
2
3
4
5
6
7
8
9
let mut counter = 0;

let result = loop {
counter += 1;

if counter == 10 {
break counter * 2;
}
};

while

1
2
3
while condition {
...;
}

for

1
2
3
for element in lst.iter() {
...;
}

所有权

鸽了,明天再写

Reference

作者

TonyCrane

发布于

2021-08-03

更新于

2021-08-23

许可协议