Compare commits
1
Commits
fa357afdd8
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44910b3d68 |
No files matched your search
@@ -0,0 +1,34 @@
|
|||||||
|
# 常用的命令
|
||||||
|
|
||||||
|
## 初始化项目
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cargo new hello_world
|
||||||
|
```
|
||||||
|
|
||||||
|
## 添加依赖
|
||||||
|
```shell
|
||||||
|
cargo add xxx
|
||||||
|
```
|
||||||
|
|
||||||
|
## 检查项目
|
||||||
|
```shell
|
||||||
|
cargo check
|
||||||
|
```
|
||||||
|
|
||||||
|
## 运行项目
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cargo run
|
||||||
|
```
|
||||||
|
|
||||||
|
## 编译项目
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cargo build
|
||||||
|
```
|
||||||
|
|
||||||
|
## 发布项目 (编译时间更长,但是会做一些优化)
|
||||||
|
```shell
|
||||||
|
cargo build --release
|
||||||
|
```
|
||||||
+547
@@ -0,0 +1,547 @@
|
|||||||
|
# Rust 语法学习
|
||||||
|
|
||||||
|
## 用例 1:猜数游戏
|
||||||
|
|
||||||
|
生成一个随机 1-100 的数并让玩家猜测
|
||||||
|
|
||||||
|
```rust
|
||||||
|
|
||||||
|
// rust默认隐式引入prelude
|
||||||
|
// 除了prelude以外都要显式引入
|
||||||
|
use rand::random;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// 使用常量定义一个偏置量
|
||||||
|
// 常量在编译时就已经确定,所以不能通过如CONST XX = XX()来初始化
|
||||||
|
// let声明的不可变变量虽然不可变,但是在编译时默认为未知的。
|
||||||
|
const BIAS: u8 = 1;
|
||||||
|
|
||||||
|
println!("guess number game");
|
||||||
|
|
||||||
|
// let: 声明变量,默认不可变
|
||||||
|
// mut:声明变量可变
|
||||||
|
// String::new(),冒号表示这是一个String类的关联函数
|
||||||
|
// 关联函数就是类似于静态方法
|
||||||
|
let secret_number = random::<u8>() + BIAS;
|
||||||
|
println!("secret number is {}", secret_number);
|
||||||
|
|
||||||
|
// mut使得变量可变
|
||||||
|
let mut user_guess: u8 = 0;
|
||||||
|
let mut user_input = String::new();
|
||||||
|
while user_guess != secret_number {
|
||||||
|
// 清空之前的输入
|
||||||
|
user_input.clear();
|
||||||
|
|
||||||
|
// io::stdin():标准输入
|
||||||
|
// read_line:读取一行
|
||||||
|
// &:取地址符号,表示引用,默认不可变
|
||||||
|
// &mut:声明可变引用
|
||||||
|
std::io::stdin().read_line(&mut user_input).expect("read fail");
|
||||||
|
// 将输入的字符串转换为数字
|
||||||
|
// user_guess = user_input.trim().parse().expect("parse fail");
|
||||||
|
// 使用 match 表达式判断用户输入的是否为数字
|
||||||
|
// 比使用if else更简洁
|
||||||
|
user_guess = match user_input.trim().parse() {
|
||||||
|
Ok(num) => num,
|
||||||
|
Err(_) => {
|
||||||
|
println!("please input a number");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 判断用户输入的数字与随机数的大小关系
|
||||||
|
// if user_guess > secret_number {
|
||||||
|
// println!("user number is too large");
|
||||||
|
// } else if user_guess < secret_number {
|
||||||
|
// println!("user number is too small");
|
||||||
|
// } else {
|
||||||
|
// println!("user number is correct");
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// 使用 match 表达式判断用户输入的数字与随机数的大小关系
|
||||||
|
// 比使用if else更简洁
|
||||||
|
match user_guess.cmp(&secret_number) {
|
||||||
|
std::cmp::Ordering::Greater => println!("user number is too large"),
|
||||||
|
std::cmp::Ordering::Less => println!("user number is too small"),
|
||||||
|
std::cmp::Ordering::Equal => {
|
||||||
|
println!("user number is correct");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
println!("user number is {}", user_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## 特性: shadow
|
||||||
|
|
||||||
|
在同一个作用域内,可以重复声明同名的变量,会覆盖之前的变量
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
let x = 5;
|
||||||
|
// 重复声明同名的变量,会覆盖之前的变量
|
||||||
|
let x = x + 1;
|
||||||
|
let x = x * 2;
|
||||||
|
println!("The value of x is: {}", x); // 12
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 类型
|
||||||
|
|
||||||
|
### 基本类型
|
||||||
|
|
||||||
|
#### 整数类型
|
||||||
|
|
||||||
|
- 整数:i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
|
||||||
|
- 整数类型范围:
|
||||||
|
- 有符号:-2^n+1 ~ 2^(n-1)-1
|
||||||
|
- 无符号:0 ~ 2^n-1
|
||||||
|
- isize, usize:取决于运行程序的计算机的架构
|
||||||
|
- 表示
|
||||||
|
- hex: 0x12345678
|
||||||
|
- oct: 0o12345678
|
||||||
|
- bin: 0b1010_1010
|
||||||
|
- Byte: b'A'
|
||||||
|
|
||||||
|
#### 浮点数类型
|
||||||
|
|
||||||
|
- 浮点数:f32, f64, 默认是 f64
|
||||||
|
- 表示
|
||||||
|
- 科学计数法:1.23e3
|
||||||
|
- 小数点:1.23
|
||||||
|
|
||||||
|
#### 布尔类型
|
||||||
|
|
||||||
|
- 布尔类型:bool
|
||||||
|
- 表示
|
||||||
|
- true, false
|
||||||
|
|
||||||
|
#### 字符类型
|
||||||
|
|
||||||
|
- 字符类型:char
|
||||||
|
- 表示
|
||||||
|
- 'a', 'A', '1', '中'
|
||||||
|
- 单引号表示
|
||||||
|
- 占用 4 字节
|
||||||
|
|
||||||
|
### 复合类型
|
||||||
|
|
||||||
|
#### 元组类型(Tuple)
|
||||||
|
|
||||||
|
- 可以将多个类型的多个值放在一个类型里
|
||||||
|
- 长度是固定的,一旦声明就无法改变
|
||||||
|
- 声明例: let tup: (i32, f64, u8) = (500, 6.4, 1);
|
||||||
|
- 访问例 1: let (x, y, z) = tup;
|
||||||
|
- 访问例 2: let x = tup.0;
|
||||||
|
|
||||||
|
#### 数组类型(Array)
|
||||||
|
|
||||||
|
- 可以将多个类型的多个值放在一个类型里
|
||||||
|
- 长度也是固定的,一旦声明就无法改变
|
||||||
|
- 想要使用有固定数量的元素时使用数组更有好处
|
||||||
|
- 声明例: let arr: [i32; 5] = [1, 2, 3, 4, 5];
|
||||||
|
- 声明例 2: let arr = [3; 5]; // 表示数组有 5 个 3
|
||||||
|
- 访问例: let x = arr[0];
|
||||||
|
- 没有 Vector 灵活
|
||||||
|
|
||||||
|
## 函数
|
||||||
|
|
||||||
|
函数名小写,单词间使用下划线进行分割
|
||||||
|
|
||||||
|
例子:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
|
||||||
|
fn f(x: i32, y: i32) -> i32 {
|
||||||
|
// 这里不加分号,因为是表达式,会返回值
|
||||||
|
// 函数默认使用最后一个表达式作为返回值
|
||||||
|
x + y
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f2(x: i32, y: i32) {
|
||||||
|
let z = {
|
||||||
|
x + y + 1
|
||||||
|
};
|
||||||
|
z
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## 控制流
|
||||||
|
|
||||||
|
### if 表达式
|
||||||
|
|
||||||
|
- 如果使用多于一个的 if-else,最好使用 match 对代码进行重构
|
||||||
|
- if 表达式是一个表达式,所以可以将其赋值给一个变量
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
let x = 5;
|
||||||
|
if x < 5 {
|
||||||
|
println!("x is less than 5");
|
||||||
|
} else if x > 5 {
|
||||||
|
println!("x is greater than 5");
|
||||||
|
} else {
|
||||||
|
println!("x is 5");
|
||||||
|
}
|
||||||
|
// 使用 match 对代码进行重构
|
||||||
|
let x = 5;
|
||||||
|
match x.cmp(&5) {
|
||||||
|
std::cmp::Ordering::Less => println!("x is less than 5"),
|
||||||
|
std::cmp::Ordering::Greater => println!("x is greater than 5"),
|
||||||
|
std::cmp::Ordering::Equal => println!("x is 5"),
|
||||||
|
}
|
||||||
|
|
||||||
|
let y = if x < 5 {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
2
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 循环
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
let mut x = 0;
|
||||||
|
while x < 5 {
|
||||||
|
println!("x is {}", x);
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
x = 0;
|
||||||
|
// 使用 .. 表示一个范围,不包含右边的数
|
||||||
|
// 实际的类型是std::ops::Range<{integer}>
|
||||||
|
// 可以通过(1..5).rev() 表示一个倒序的范围
|
||||||
|
for x in 0..5 {
|
||||||
|
println!("x is {}", x);
|
||||||
|
}
|
||||||
|
const A: [i32; 5] = [1, 2, 3, 4, 5];
|
||||||
|
// iter 方法返回一个迭代器,迭代器是一个可以遍历集合的对象
|
||||||
|
for x in A.iter() {
|
||||||
|
println!("x is {}", x);
|
||||||
|
}
|
||||||
|
x = 0;
|
||||||
|
loop {
|
||||||
|
println!("x is {}", x);
|
||||||
|
x += 1;
|
||||||
|
if x > 5 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// loop 表达式是一个表达式,所以可以将其赋值给一个变量
|
||||||
|
let result = loop {
|
||||||
|
if x > 5 {
|
||||||
|
break x * 2;
|
||||||
|
}
|
||||||
|
x += 1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 所有权
|
||||||
|
|
||||||
|
- 内存管理分为两个部分:栈和堆
|
||||||
|
- 所有权是 Rust 最独特的特性之一
|
||||||
|
- 在 Rust 中,每个值都有一个变量,这个变量被称为所有者
|
||||||
|
- 每个值在任意时刻有且只有一个所有者
|
||||||
|
- 当所有者离开 scope(作用域),这个值将被删除
|
||||||
|
|
||||||
|
### 作用域
|
||||||
|
|
||||||
|
例:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
{
|
||||||
|
let x = 5;
|
||||||
|
println!("x is {}", x);
|
||||||
|
}
|
||||||
|
// x 已经离开作用域
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### copy trait
|
||||||
|
|
||||||
|
- 赋值要么发生移动,要么发生复制
|
||||||
|
- Rust 中的基本类型都实现了 copy trait
|
||||||
|
- 如果一个类型实现了 copy trait,则旧的变量在赋值后仍然可以使用
|
||||||
|
- 否则就像下面的 String 一样,赋值以后旧的变量会失效
|
||||||
|
- 内容全为已实现 copy 的 tuple 也是可 copy 的
|
||||||
|
|
||||||
|
### 所有权和函数
|
||||||
|
|
||||||
|
- rust 函数传参与赋值操作类似
|
||||||
|
- 所以可能发生移动,使得一些变量失效
|
||||||
|
- 返回值时所有权也很发生移动或复制
|
||||||
|
- 一个变量的所有权总是遵循同样的模式
|
||||||
|
- 把一个值赋给其他变量的时候会发生移动
|
||||||
|
- 当一个包含 heap 数据的变量离开作用域时。这个值就会被 drop 函数删除
|
||||||
|
- 除非其所有权发生了转移
|
||||||
|
|
||||||
|
例:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
let s = String::from("hello");
|
||||||
|
takes_ownership(s);
|
||||||
|
// 这里会报错,因为s已经失效了
|
||||||
|
// println!("{}", s);
|
||||||
|
let x = 5;
|
||||||
|
makes_copy(x);
|
||||||
|
// 这里不会报错,因为x仍然可以使用
|
||||||
|
println!("{}", x);
|
||||||
|
|
||||||
|
let s1 = generates_string();
|
||||||
|
|
||||||
|
let s2 = String::from("hello");
|
||||||
|
|
||||||
|
let s3 = takes_and_gives_back(s2);
|
||||||
|
println!("{}", s1);
|
||||||
|
// 这里会报错,因为s2已经失效了
|
||||||
|
println!("{}", s2);
|
||||||
|
println!("{}", s3);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn takes_and_gives_back(a_string: String) -> String {
|
||||||
|
a_string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generates_string() -> String {
|
||||||
|
let s = String::from("hello");
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn makes_copy(x: i32) {
|
||||||
|
println!("{}", x);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn takes_ownership(some_string: String) {
|
||||||
|
println!("{}", some_string);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 引用和借用
|
||||||
|
|
||||||
|
- 引用是一个指向某个值的指针
|
||||||
|
- 引用不会获取到值的所有权
|
||||||
|
- 引用的变量默认是不可变的
|
||||||
|
- 引用的变量可以通过 mut 关键字声明为可变的
|
||||||
|
- 特定的作用域内,一个变量只能有一个可变引用
|
||||||
|
- 不可同时拥有可变引用与不可变引用
|
||||||
|
- 不可变引用可以有多个
|
||||||
|
- rust 在编译时会防止悬空指针的出现
|
||||||
|
例
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
let s1 = String::from("hello");
|
||||||
|
// 这里的s2是一个引用,指向s1
|
||||||
|
let len = calculate_length(&s1);
|
||||||
|
change_string(&mut s1);
|
||||||
|
println!("{}", s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calculate_length(s: &String) -> usize {
|
||||||
|
s.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_string(s: &mut String) {
|
||||||
|
s.push_str(", world");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## slice 切片
|
||||||
|
|
||||||
|
- slice 是一个引用,指向一个字符串/数组的一部分
|
||||||
|
- 定义函数时使用字符串切片(&str)来代替字符串引用会使我们的 api 更加通用且不会损失任何功能
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
let s = String::from("hello world");
|
||||||
|
let wordIndex = first_word(&s);
|
||||||
|
let hello = &s[0..5];
|
||||||
|
let world = &s[6..11];
|
||||||
|
// 这里会报错,因为clear会导致可变,但是 s已被不可变引用
|
||||||
|
s.clear();
|
||||||
|
let a: [u8; 5] = [1, 2, 3, 4, 5];
|
||||||
|
let slice = &a[0..2];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn first_word(s: &str) -> usize {
|
||||||
|
let bytes = s.as_bytes();
|
||||||
|
for (i, &item) in bytes.iter().enumerate() {
|
||||||
|
if item == b' ' {
|
||||||
|
return &s[i..];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&s[..]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## String
|
||||||
|
|
||||||
|
- 相比于使用双引号创建的字符串,使用 String 类型可以动态地分配内存
|
||||||
|
- String 是一个可变的字符串类型
|
||||||
|
- String 是一个堆上的字符串,而不是栈上的字符串
|
||||||
|
- 底层实现上:
|
||||||
|
- String 是一个结构体,包含一个指向堆上的字符串的指针和一个长度,一个容量
|
||||||
|
- 结构体储存在栈上
|
||||||
|
- 真实的字符串储存在堆上
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
// 在heap上分配内存了
|
||||||
|
let mut s = String::from("hello");
|
||||||
|
// 和js类似,s1和s实际上是同一个字符串
|
||||||
|
// 但是因为一些所有权的问题,所以在s1生效以后,s就失效了
|
||||||
|
let s1 = s;
|
||||||
|
// 克隆消耗资源,但是原来的不会失效了
|
||||||
|
let s2 = s1.clone();
|
||||||
|
// 这样会报错,因为s已经失效了
|
||||||
|
s.push_str(", world");
|
||||||
|
s1.push_str(", world");
|
||||||
|
println!("s is {}", s1);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## struct 结构体
|
||||||
|
|
||||||
|
- 结构体是一个自定义的类型
|
||||||
|
- 一旦结构体是可变的,那么结构体的所有字段就是可变的
|
||||||
|
- 只要 struct 是有效的,则里面的引用也都是有效的
|
||||||
|
|
||||||
|
```rust
|
||||||
|
struct User {
|
||||||
|
name: String,
|
||||||
|
age: u8,
|
||||||
|
id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
// tuple struct 元组结构体
|
||||||
|
struct Color(i32, i32, i32)
|
||||||
|
|
||||||
|
// 这样可以将结构体打印出来
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Rectangle {
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl关键字用于为结构体实现接口或者关联函数或者方法
|
||||||
|
impl Rectangle {
|
||||||
|
fn area(&self) -> u32 {
|
||||||
|
self.width * self.height
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_hold(&self, other: &Rectangle) -> bool {
|
||||||
|
self.width > other.width && self.height > other.height
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关联函数,不需要实例化就可以调用,通常用于创建结构体
|
||||||
|
// 类似于静态方法
|
||||||
|
fn square(size: u32) -> Rectangle {
|
||||||
|
Rectangle {
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let id: u32 = 1;
|
||||||
|
let user = User {
|
||||||
|
name: String::from("hello"),
|
||||||
|
age: 18,
|
||||||
|
id, // 如果字段名和变量名相同,可以省略变量名
|
||||||
|
};
|
||||||
|
let user2 = User {
|
||||||
|
name: String::from("world"),
|
||||||
|
id: 2,
|
||||||
|
..user //struct更新语法
|
||||||
|
};
|
||||||
|
println!("user is {}", user.name);
|
||||||
|
|
||||||
|
let color = Color(255, 0, 0);
|
||||||
|
let rect = Rectangle {
|
||||||
|
width: 10,
|
||||||
|
height: 20,
|
||||||
|
};
|
||||||
|
let rect2 = Rectangle {
|
||||||
|
width: 5,
|
||||||
|
height: 10,
|
||||||
|
};
|
||||||
|
println!("rect is {:#?}", rect);
|
||||||
|
println!("rect area is {}", rect.area());
|
||||||
|
println!("rect can hold rect2? {}", rect.can_hold(&rect2));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 枚举
|
||||||
|
|
||||||
|
- 枚举是一个自定义的类型
|
||||||
|
例
|
||||||
|
|
||||||
|
```rust
|
||||||
|
enum IpAddr {
|
||||||
|
V4(u8, u8, u8, u8),
|
||||||
|
V6(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let home = IpAddr::V4(127, 0, 0, 1);
|
||||||
|
let loopback = IpAddr::V6((String::from("::1")));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Option
|
||||||
|
|
||||||
|
- Option 是一个枚举类型,表示一个值可能不存在
|
||||||
|
- 包含在预导入库中,可以直接使用
|
||||||
|
```rust
|
||||||
|
enum Option<T> {
|
||||||
|
Some(T),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 如 let x: Option<i32> = None;
|
||||||
|
- 通过unwrap方法可以获取到Some的值
|
||||||
|
|
||||||
|
## match
|
||||||
|
- match可以提供一种匹配
|
||||||
|
|
||||||
|
```rust
|
||||||
|
enum UsState {
|
||||||
|
Alabama,
|
||||||
|
Alaska,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Coin {
|
||||||
|
Penny,
|
||||||
|
Nickel,
|
||||||
|
Dime,
|
||||||
|
Quarter(UsState),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_in_cents(coin: Coin) -> u8 {
|
||||||
|
match coin {
|
||||||
|
Coin::Penny => 1,
|
||||||
|
Coin::Nickel => 5,
|
||||||
|
Coin::Dime => 10,
|
||||||
|
Coin::Quarter(state) => {
|
||||||
|
println!("State quarter from {:?}!", state);
|
||||||
|
25
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let coin = Coin::Quarter(UsState::Alaska);
|
||||||
|
println!("value_in_cents is {}", value_in_cents(coin));
|
||||||
|
}
|
||||||
|
```
|
||||||
File renamed without changes.
Reference in new issue
Block a user