Rust#
具体介绍看一下 百度百科
简单来说,和 C++ 和 C 一样没有 GC, 但是又不用去管理内存的编程语言。
学习文档#
https://kaisery.github.io/trpl-zh-cn/ch20-01-single-threaded.html https://course.rs/about-book.html
Cargo 包管理工具#
cargo new helll__cargo # 新建项目
cargo build # 编译项目cargo build --release # 优化编译项目
cargo run # 编译并运行项目
cargo check # 检查是否能通过编译,并不生成可执行文件
[package]name = "hello_cargo"version = "0.1.0"edition = "2021"
[dependencies]
match#
match 会开始一个新作用域
let dice_roll = 9
match dice_roll { 1 | 2 => println!("one or two"), 3 => add_fancy_hat(), 4..=6 => println!("one through five"), // 匹配 4 <= x <= 6 7 => remove_fancy_hat(), other => move_player(other), // other 会匹配 3 和 7 之外的所有值}
match dice_roll { 3 => add_fancy_hat(), 7 => remove_fancy_hat(), _ => reroll(), // _ 匹配任意值而不绑定到该值}
return 写不写#
https://cloud.tencent.com/developer/article/1559616
fn r(n: i32) -> i32 { if n > 0 { 0 } 1}
编译不通过, expected ()
, found integer
原因:
rust 编译器认为函数体是由一个语句和表达式组成的 if n > 0 { 0 } 和 1 构成的。
因为没有 else,所以它不认为 if 代码块是表达式的一部份 所以做为函数返回值的是 1 这个表达式
第一个语句中的代码块的最后一行是表达式,但其它本身又不是条件赋值语句。另外 if 作为 rust 的表达式,要求 if 和 else 两部分类型相同,如果缺少 else 部分,else 部分默认是 (), 这样就要求 if 部分求值结果也是()。
解决方法:
- 把 1 放进 else 里面。
- 在 0 前面显式的加上 return。
生命周期#
// 没有 'a 时,函数不知道返回值的引用会不会返回过期的引用,为了保障自己传递出去的值是正常的,需要添加相同的生命周期告诉编译器。fn longer<'a>(s1: &'a str, s2: &'a str) -> &'a str { if s2.len() > s1.len() { s2 } else { s1 }}
fn main() { let r; { let s1 = "rust"; let s2 = "ecmascript"; r = longer(s1, s2); // s1,s2 已经 copy 给了 r。 } println!("{} is longer", r);}
宏#
https://www.bookstack.cn/read/DaseinPhaos-tlborm-chinese/README.md
macro_rules!#
宏选择器
- item:条目,例如函数、结构、模块等
- block:代码块
- stmt:语句
- pat:模式
- expr:表达式
- ty:类型
- ident:标识符
- path:路径,例如 foo、 ::std::mem::replace, transmute::<_, int>, …
- meta:元信息条目,例如 #[…]和 #![rust macro…] 属性
- tt:词条树
macro_rules! yo { ($name: expr) => { println!("Yo {}!", $name); }}
//TODO// macro_rules! hei {// ($($name: expr), *) => {// println!("Hei {}!", $name);// }// }// hei!("Finn", "Jake", "PB");
fn main() { yo!("Finn");}
库#
syn 解析库
quote 生成库
&
Rust | 含义 |
---|---|
a: &T | 都不能修改 |
mut a:&T | 不能修改 a 指向的内容 |
a: &mut T | 不能修改 a |
mut a:&mut T | 都能修改 |
dyn#
dyn 是 trait 对象类型的前缀,dynamic 的缩写。比如你有一个 trait 名字叫做 Writable,你可以用 dyn Writable 表示实现了 Writable 特征的 struct。
dyn 关键字用于强调调用相关特征的方法是动态分配的,即运行时才知道调用的是哪个实现了特征的结构体(类似 java 的运行时多态)。
不像范型参数或者 impl Trait,编译器无法知道调用的时候被传递的具体类型是什么。也就是说,类型信息被擦除了。就其本身而言,一个 dyn Trait 引用包含两个指针。一个指针指向数据(比如一个结构体的实例)。另一个指针指向方法名与函数指针的 map(也叫做虚方法表)。
在运行时,当需要调用 dyn Trait 上的方法的时候,会查询虚方法表以获取函数指针,然后去调用查找到的函数指针。
使用 dyn Trait 的一个例子:
fn main() { let mut personList: Vec<Box<dyn Role>> = Vec::new(); let student = Student; let teacher = Teacher;
personList.push(Box::new(student)); personList.push(Box::new(teacher));
for p in personList { p.print_role(); }}
struct Student;
struct Teacher;
trait Role { fn print_role(&self);}
impl Role for Student { fn print_role(&self) { println!("role is student"); }}
impl Role for Teacher { fn print_role(&self) { println!("role is teacher"); }}
异步#
异步库:tokio, soml
Fn FnMut FnOnce#
闭包被分为了三种类型,列举如下
Fn(&self)
可以运行多次的,但不可以修改捕获变量的值FnMut(&mut self)
闭包是可变借用,可以修改捕获变量,但不会释放该变量,可以运行多次FnOnce(self)
闭包会获取变量的所有权,运行之后就会被释放
Box Rc Arc Cell RefCell 智能指针#
Box#
Box<T>
指向在类型为 T 的堆上分配的数据。Box<T>
允许将数据存储在堆而不是栈上。
Rc Arc#
Rc(reference counting 引用计数) 是一种共享所有权智能指针。克隆了一份智能指针 Rc,并将该智能指针的引用计数增加到 2。适用于单线程
Arc(Atomic Rc 原子引用计数) 是一种线程安全的共享所有权智能指针。适用于多线程(由于 Rc<T>
需要管理引用计数,但是该计数器并没有使用任何并发原语,因此无法实现原子化的计数操作,最终会导致计数错误。)
Cell RefCell#
Cell 和 RefCell 在功能上没有区别,区别在于 Cell<T>
适用于 T 实现 Copy 的情况
use std::cell::Cell;fn main() { let c = Cell::new("asdf"); let one = c.get(); c.set("qwer"); // 不写 mut 也可以修改 let two = c.get(); println!("{},{}", one, two);}
Cell 是一种提供内部可变性的容器,Cell 没有额外的性能损耗。
RefCell 是一种提供内部可变性的容器
Cow#
Cow 是一种写时复制的枚举体的智能指针
Deref 解引用#
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> { type Target = T;
fn deref(&self) -> &Self::Target { &self.0 }}
#[test]fn main() { let my = MyBox("ss");
/// `MyBox` 没有实现 `to_string()` 也可以调用 my.to_string();}
Drop 释放资源#
结构体#
标准的结构体 —— C struct
struct Person { name: String, age: i32, address: String,}
简略的结构体 —— tuple struct
struct Person(String, i32, String);
最简略的结构体 —— unit struct
struct Person;
字符串格式化#
format!("Hello"); // => "Hello"format!("Hello, {}!", "world"); // => "Hello, world!"format!("The number is {}", 1); // => "The number is 1"format!("{:?}", (3, 4)); // => "(3, 4)"format!("{value}", value=4); // => "4"let people = "Rustaceans";format!("Hello {people}!"); // => "Hello Rustaceans!"format!("{} {}", 1, 2); // => "1 2"format!("{:04}", 42); // => "0042" with leading zerosformat!("{:#?}", (100, 200)); // => "( // 100, // 200, // )"
// All of these print "Hello x !"println!("Hello {:5}!", "x");println!("Hello {:1$}!", "x", 5);println!("Hello {1:0$}!", 5, "x");println!("Hello {:width$}!", "x", width = 5);let width = 5;println!("Hello {:width$}!", "x");
小数 Precision#
// Hello {arg 0 ("x")} is {arg 1 (0.01) with precision specified inline (5)}println!("Hello {0} is {1:.5}", "x", 0.01);
// Hello {arg 1 ("x")} is {arg 2 (0.01) with precision specified in arg 0 (5)}println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
// Hello {arg 0 ("x")} is {arg 2 (0.01) with precision specified in arg 1 (5)}println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
// Hello {next arg -> arg 0 ("x")} is {second of next two args -> arg 2 (0.01) with precision// specified in first of next two args -> arg 1 (5)}println!("Hello {} is {:.*}", "x", 5, 0.01);
// Hello {arg 1 ("x")} is {arg 2 (0.01) with precision// specified in next arg -> arg 0 (5)}println!("Hello {1} is {2:.*}", 5, "x", 0.01);
// Hello {next arg -> arg 0 ("x")} is {arg 2 (0.01) with precision// specified in next arg -> arg 1 (5)}println!("Hello {} is {2:.*}", "x", 5, 0.01);
// Hello {next arg -> arg 0 ("x")} is {arg "number" (0.01) with precision specified// in arg "prec" (5)}println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01);
GAT#
GAT 其实是 Generic Associated Types 的缩写, 即泛型关联类型。
https://zhuanlan.zhihu.com/p/580996117
chrono#
时间库
格式化#
Spec | Example | Description |
---|---|---|
%Y | 2001 | 年份 |
%C | 20 | 年份的高两位 |
%y | 01 | 年份的低两位 |
%m | 07 | 月份 |
%b | Jul | 月份 3 个字母 |
%d | 08 | 日 |
%a | Sun | 星期 |
%H | 00 | 24 制小时 |
%M | 34 | 分钟 |
%S | 60 | 秒 |
https://docs.rs/chrono/latest/chrono/format/strftime/index.html
trait#
ParitalOrd / Ord / ParitalEq / Eq#
对于集合 X 中的元素 a, b, c,
- 如果 a < b 则一定有 !(a > b);反之,若 a > b,则一定有 !(a < b),称为反对称性。
- 如果 a < b 且 b < c 则 a < c,称为传递性。
- 对于 X 中的所有元素,都存在 a < b 或 a > b 或者 a == b,三者必居其一,称为完全性。
对于 X 中的元素具备上述前两特征称为偏序,同时具备所有特征称为全序。
ParitalOrd 和 ParitalEq 为偏序
因为浮点数中有特殊的值 NaN,所有浮点数不具备全序特征。
PhantomData<T>
幽灵数据#
零大小类型的标记结构体
未使用的生命周期#
struct Slice<'a, T> { start: *const T, end: *const T}
不允许存在声明 'a
, 但未使用。修改如下:
struct Slice<'a, T: 'a> { start: *const T, end: *const T, _marker: PhantomData<&'a T>}
未使用的类型#
struct SendCh<T, C: Sender<T>> { ch: C, name: &'static str, marker: PhantomData<T>}
Option enum and Error enum#
Option and_then#
pub const fn and_then<U, F>(self, f: F) -> Option<U>where F: FnOnce(T) -> Option<U> + Destruct
assert_eq!(Some(1).and_then(|_| Some(2)), Some(2))
对 Some 里的值进行变换,并扁平
Option map#
pub const fn map<U, F>(self, f: F) -> Option<U>where F: ~const FnOnce(T) -> U, F: ~const Destruct,
assert_eq!(Some(1).map(|_| 2), Some(2))
对 Some 里的值进行变换
Option unwrap_or#
pub const fn unwrap_or(self, default: T) -> Twhere T: ~const Destruct
assert_eq!(Some("car").unwrap_or("bike"), "car");assert_eq!(None.unwrap_or("bike"), "bike");
为 None 使用默认值
Option unwrap_or_else#
pub const fn unwrap_or_else<F>(self, f: F) -> Twhere F: ~const FnOnce() -> T, F: ~const Destruct
为 None 使用函数生成默认值
Option unwrap_or_default#
pub const fn unwrap_or_default(self) -> Twhere T: ~const Default
自动使用 Default::default()
生成默认值