From 44910b3d680253b100d9d9eee247cc0ff25999b0 Mon Sep 17 00:00:00 2001 From: Miao_Spring <539943419@qq.com> Date: Sat, 14 Dec 2024 22:20:19 +0800 Subject: [PATCH] add rust1 --- rust/aboutCargo.md | 34 ++ rust/rust1.md | 547 ++++++++++++++++++++++++ aboutWebRTC.md => webRTC/aboutWebRTC.md | 0 3 files changed, 581 insertions(+) create mode 100644 rust/aboutCargo.md create mode 100644 rust/rust1.md rename aboutWebRTC.md => webRTC/aboutWebRTC.md (100%) diff --git a/rust/aboutCargo.md b/rust/aboutCargo.md new file mode 100644 index 0000000..1832f25 --- /dev/null +++ b/rust/aboutCargo.md @@ -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 +``` \ No newline at end of file diff --git a/rust/rust1.md b/rust/rust1.md new file mode 100644 index 0000000..1fe3c8d --- /dev/null +++ b/rust/rust1.md @@ -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::() + 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 { + Some(T), + None, +} +``` +- 如 let x: Option = 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)); +} +``` \ No newline at end of file diff --git a/aboutWebRTC.md b/webRTC/aboutWebRTC.md similarity index 100% rename from aboutWebRTC.md rename to webRTC/aboutWebRTC.md