Overview
rust中的一些技巧
tips
引用与借用的区别
创建引用的行为称为借用(borrowing)
裸指针和引用的相互转换
引用可以隐式或显式地转换为裸指针
- 显式:
let a: *const i32 = &b as *const i32;
- 隐式:
let a: *cosnt i32 = &b;
1 | // Explicit cast: |
裸指针转引用:
- 指针解引用获取对象:
*p
- 获取对象的引用:
&*p
,&mut *p
- 裸指针解引用是unsafe操作
1 | unsafe { |
rust中打印变量地址
先将变量的引用&val
转换为相应的裸指针*const T
或*mut T
,然后再转换成usize
1 | // 打印裸指针 |
lang
声明式宏
macro_rules
未来将会被废弃
- 使用
#[macro_export]
注释将宏导出 - 使用
macro_rules! NAME {}
进行宏定义
1 |
|
$x:expr
表示匹配任何表达式,并命名为x
,使用$x
访问$()
表示里面的内容会匹配多次,$(),*
表示有潜在逗号分隔,会匹配多次()=>{}
,不用$
就只匹配一次{}
中的内容是要展开的表达式- 使用
$()*
表示根据匹配次数生成对应代码
- 使用
错误处理
unwrap
取出Some/OK(e)等否则panicmap(self, F)
返回None或F处理后的Option:Some(F(T))
and_then(self, F)
的区别, map总是rewraped with Some, 而and_then
可以任意类型
unwrap_or(T, default)
, 取出Some或None时返回default
- Result: richer version of Option
- Multiple error type
- 类型转换:
ok_or()
Option转Result - TODO: Box
- 类型转换:
try
和?
宏- 如果错误返回错误(即返回), 常用
?
- 如果错误返回错误(即返回), 常用
rust引入了很多现代的抽象来消除Undefine Behavior,如Result
, Option
。而这些抽象可能需要很多重复的繁琐的”分支处理”,如:
1 | match result { |
于是Rust由引入了一些方便程序员的函数。上面的代码就得到了简化
unwrap()
,对于一个Result
或Option
或实现了相关trait的,返回内容物,否则panicexpect("")
,类似unwrap,但是可以指定panic的作为信息
对于不让用户自己处理的错误可以”抛出”,即作为函数返回,而不是立刻处理,类似java的throw
1 | let f = File::open("path"); |
rust中的简化是使用?
操作符,如let f = File::open("path")?
将错误返回。需要注意的是使用?
操作符的函数的返回类型必须实现了响应trait。
?
如果”错误”返回出去,否则拿到内容物- 一个函数可能返回多种错误类型,这样它的返回值可以使用
Box<dyn Error>
,即实现了该trait的对象,或者能实现from
转换掉
因为?
的存在,必定会返回一个result,所以原本无返回的函数还要返回OK(())
类型转换
https://course.rs/basic/converse.html
- 自动类型推导的过程
mem::transmute<T, U>(T) -> U
mem::transmute_copy<T, U>(T) -> U
, 甚至没有大小检测
Rc
多所有权的场景, 如树, 图
Rc::clone(&a)
增加引用计数(浅拷贝)a.clone()
, (深拷贝)Rc::strong_count(&a)
获取强引用计数Rc::weak_count(&a)
获取弱引用计数
1 | enum List { |
RefCell
不可变引用一个改变数据之:内部可变性
“data race = undefine behavior = rust 借用规则”
rust 借用规则(读写锁): 可以存在一个可变引用(借用)或多个不可变引用。rust通过这点来消除undefine behavior
RefCell<T>
内部通过unsafe代码来维护可变引用和不可变引用的计数,从而绕过编译器借用规则检查,在运行时执行借用规则检测,一旦出错将会panic。
RefCell<T>::borrow()
返回一个不可变引用(借用)Ref<T>
计数加1Ref<T>
离开作用域,计数减1
RefCell<T>::borrow_mut()
返回一个可变引用(借用)RefMut<T>
计数加1RefMut<T>
离开作用域,计数减1
运行时违反借用规则将panic
- Rc + RefCell
- 多所有权内部可变场景
1 | let value = Rc::new(RefCell::new(5)); |
- Cell
, 通过复制来实现内部可变
HashMap
use std::collections::HashMap;
妙用entry(key).or_insert(value)
增
1 | map.insert(k, v); |
删
改, or_insert
很精髓
1 | // map[k]++ |
查
1 | for (k, v) in &map { |
zip
- 合并两个iter, 成一个元素为pair的iter, 如
[(iter1.1, iter2.1), (iter1.2, iter2.2), ...]
- 不够一个pair将称为None
- 格式:
iter = iter1.iter().zip(iter2.iter())
- 可以使用map再将pair变为其他元素
map(|(&a, &b)| vec![a, b])
Send + Sync
- 实现
Send
的类型可以线程间安全传递所有权 - 实现
Sync
的类型可以线程间安全共享(引用) - 手动实现
Send + Sync
不安全, 好在大多数类型实现了
tuple
元组一个个.
太麻烦了, 直接解包。可以使用@
运算符
1 | fn t(tuple: (i32, i32, i32)) { |
内敛汇编
1 | asm!( |
- 前半部””包裹的字段: 汇编模板
{}
, placeholder, 类似println!()
, 可以指定index也可以不[]
, 表示一个内存地址
- 后半部rust代码: 输入输出参数
in(reg) new
, 让编译器决定一个通用寄存器来保存newout(reg)
, 同理, 表示输出, 需要mut- 同理还有
inout
,lateout
- option参数
- 如可以指定使用AT&T还是intel格式等
范围match
match中加if
1 | match (count) { |
match中的或操作
1 | match (count) { |