rust

Table of contents

Summary

针对概念性的,如果不看就会忘掉的东西 并且对相对比较复杂的地方需要做一下自己的理解 不要把精力放在过于花哨的类型系统和语法糖,只需要知道有这个东西就行 这里根据我看到的东西查缺补漏,之前一直没有做系统化的整理

循环控制结构

for/while/loop break 可以通过label 标记作用域跳出去

match

https://doc.rust-lang.org/stable/reference/expressions/match-expr.html

生命周期

更小的生命周期可以被比他大的生命周期覆盖 ‘a 能被 ‘static替代 衍生话题就是hrtb,实际上rust的subtyping只有在生命周期有这个概念 即需求’a生命周期的能用比他更大的’b来实现 这个貌似内部是通过hrtb for<‘a>这样去在调用者生成’a,延长到跟更长的生命周期里面去,或者说调用者的生命周期(这个理解需要后续确认) 生命周期的逆变 协变 https://zhuanlan.zhihu.com/p/682880532 逆变的话就可以变成fn(&str)->impl ToString 参数可以变成impl ToString, implToString->string

A <: B 代表A是B的子类型 A -> BA 为参数类型, 以 B 为返回值类型的函数类型 x : A x是一个变量, 其类型为A

Drop Check

类似C++的RAII 为了使泛型类型能够正确实现 drop,其泛型参数必须严格地比其存活时间长。 **For a generic type to soundly implement drop, its generics arguments must strictly outlive it. drop order 顺序

dyn Trait

虚表结构 多重继承里面就必须在保存一个指向虚表的指针 从实践来说的话就是如果使用组合继承的dyn Trait 是有一定性能上的影响的 https://lancern.xyz/posts/2024/01/rust-vtable

+-------------------------------+
| fn drop_in_place(*mut T)      |
+-------------------------------+
| size of T                     |
+-------------------------------+
| align of T                    |
+-------------------------------+
| fn <T as Grand>::grand_fun1   |
+-------------------------------+
| fn <T as Grand>::grand_fun2   |
+-------------------------------+
| fn <T as Parent>::parent_fun1 |
+-------------------------------+
| fn <T as Parent>::parent_fun2 |
+-------------------------------+
| fn <T as Trait>::fun          |
+-------------------------------+

Specialization

这个理解成对Trait 的方法实现默认的不完全方法 可以通过泛型参数T的约束或者具体的类型来覆盖 目前可以通过mini specialization 开启

Union

可能会用到?

Atomic相关

基本是C++的心智模型

try-trait v2

没仔细看,但是这个貌似把result,option 等等全部做了一个抽象

1pub trait Try: FromResidual {
2    type Output;
3    type Residual;
4
5    // Required methods
6    fn from_output(output: Self::Output) -> Self;
7    fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
8}

ManuallyDrop

延迟Drop,对应的还有修改drop的行为

PhantomData

伪造生命周期或者各种东西 也可以用来模拟持有某一个数据的所有权

Future Pin trait &Pin Project

Future表现为一个通过不断调用poll Pending直到Ready(T)的一个抽象定义

MaybeUninit

延迟初始化,也就是我可以一部分初始化 比如提前声明足够大的CAP

Unsafe

如果用上unsafe跟C++没差了 如果你能证明生命周期上没问题的话你可以自己绕过去

temporary-lifetimes-in-tail-expressions

https://rust-lang.github.io/rfcs/3606-temporary-lifetimes-in-tail-expressions.html 作为解决方法之一是super let ,rust目前在不同的语句里面的释放周期并没有一致的规则 可能会导致死锁

NicheOptimization

rust 会通过各种方式记录访问的值域,如果用不到的值域就会被用去做这个优化(enum) https://www.0xatticus.com/posts/understanding_rust_niche/

precise-capturing

用于指定哪些泛型参数应在类似 RPIT 的 impl Trait 类型中捕获 比如目前不允许嵌套透明对象中间捕获更高的生命周期可以通过use<> 来防止捕获进而通过编译 https://rust-lang.github.io/rfcs/3617-precise-capturing.html

可变参数泛型

https://github.com/rust-lang/lang-team/blob/master/src/design_notes/variadic_generics.md frunk 可以设计一个tuple来实现一个非同质的列表,并且可以编译期去指定他的类型名称(利用自动的函数推导) 目前我理解的rust实现的方案是 Tuple<T1,T2….Tn>=>Tupe<T1,Tuple<T2,….>> 这个也可以在axum和bevy中看到 对于想实现impl Mytrait<(T1)> for T …直到T1,T2,T3….Tn只能使用宏来实现 这个在axum的handler模型里面有见到过 这个也是属于万恶之源的一部分,只能使用形如这种形式来做到 e.g. axum

 1macro_rules! all_the_tuples {
 2    ($name:ident) => {
 3        $name!([], T1);
 4        $name!([T1], T2);
 5        $name!([T1, T2], T3);
 6        $name!([T1, T2, T3], T4);
 7        $name!([T1, T2, T3, T4], T5);
 8        $name!([T1, T2, T3, T4, T5], T6);
 9        $name!([T1, T2, T3, T4, T5, T6], T7);
10        $name!([T1, T2, T3, T4, T5, T6, T7], T8);
11        $name!([T1, T2, T3, T4, T5, T6, T7, T8], T9);
12        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9], T10);
13        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T11);
14        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], T12);
15        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], T13);
16        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], T14);
17        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], T15);
18        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], T16);
19    };
20}

ZST/DST

trait object & str,[u8] ZST=> () 还有enum sth{}

Substructural Types

https://faultlore.com/blah/linear-rust/ 需要再读一读

  1. can be used any number of times (no name - the default) 可以使用任意次数(无名称 - 默认) Copy 和Clone
  2. can’t be used more than once (affine™) 不能使用超过一次(affine™) <=1 当我移动了就不能用之前的变量,以及变量遮蔽
  3. must be used at least once (relevant™ - this one is a decent name) >=1 必须至少使用一次(relevant™ - 这是一个不错的名字) drop 和lint就是这个性质 dorp可以通过mem::forget这样去移除行为
  4. must be used exactly once (linear™) =1 必须使用一次(线性™)

Autodiff

自动计算微分 比如说

1fn f(x: f32) -> f32{
2 x * x
3}

可以自动计算这个

1fn df(x: f32) -> (f32, f32) {
2 (x*x, 2.0 * x)
3}

https://www.reddit.com/r/rust/comments/1h1b1po/using_stdautodiff_to_replace_jax/ 在Python/JAX中一般使用的时候使用的是jit编译时间可能需要数小时甚至数天 Rust 的 autodiff 可以在大约 30 分钟内编译出等效的 Rust 代码 具体工作层级是在 Enzyme https://enzyme.mit.edu/ llvm ir

内部可变性

Rc Weak UniqueRc Arc RefCell & Cell & UnsafeCell 由于 Rustmutable 特性,一个结构体中的字段,要么全都是 immutable,要么全部是 mutable不支持针对部分字段进行设置。比如,在一个 struct 中,可能只有个别的字段需要修改,而其他字段并不需要修改,为了一个字段而将整个 struct 变为 &mut 也是不合理的。 所以,实现 内部可变性CellRefCell 正是为了解决诸如这类问题存在的,通过它们可以实现 struct 部分字段可变,而不用将整个 struct 设置为 mutable

异步

主要是以tokio为主的异步库 然后和thread-per-core 类型的特殊异步库 以及使用了Io_uring的特殊库=>monoio linux 包括epoll,poll,

trait 泛型

Send/Sync

Send 是 我可以将其移动到另一个线程而不创建非线程安全的隐藏共享状态吗? Rc 移动后保持共享状态

Sync 是 多个线程是否可以保存对此的引用,而不会发生突变竞争(当且仅当&T是Send的时候T才是Sync)

特例:

e.g. 通过通过libloading载入dll,为了防止线程局部变量出问题!Send(需要由创建他的线程释放),!Sync(并没有做读写访问控制)

e.g. MutexGuard<T> 由于pthread平台限制(如果你把它发送到别的线程那么析构函数会在被发送到的线程执行,但是你可以Send &MutexGuard<T>) !Send Sync(因为要Deref)

https://blog.cuongle.dev/p/this-sendsync-secret-separates-professional-and-amateur

FFI

过程宏

能不用quote还是别用 因为这个会极大的印象展开时间

tt咀嚼机

奇怪语法糖

泛型相关

HRTB

具体表现是for<‘a>:Trait<‘a> 将生命周期推迟到调用者来决定 最经典是serde里面的使用

 1//将生命周期推迟到调用者来决定
 2serde DeserializeOwned
 3
 4fn with_nested_refcell<'nested> (
 5   nested: &'nested RefCell<RefCell<str>>,
 6   f: for<'arg> fn(&'arg str), // ≈ fn<'arg> (&'arg str),
 7)
 8{
 9   f(&*nested.borrow().borrow())
10}

RPIT

return position impl Trait RPIT 并不是泛型

1fn test_rpit() -> impl Iterator<Item = i32> {    
2	 [1, 2, 3, 4].into_iter() 
3 }

GAT

泛型关联类型

1trait ConvertTo: Sized {
2     type Inner;     
3     type Output<Item>     
4     where         
5	     Item: From<Self::Inner>;      
6	fn convert_to<U>(self) -> Self::Output<U>
7	where
8	        U: From<Self::Inner>; 
9}

我可以将函数上面的泛型类型参数U和Output泛型类型参数绑定到一起(生命周期什么的都可以传递过去了)

RPITIT

Return Position impl Trait In Traits RPITIT 解糖为关联类型或 GAT

AFIT

rust的async函数脱糖目标是RPIT(也是#[async_trait] expend的结果)

1async fn get_one()->i32{
2	1
3}
4//脱糖到
5fn get_one() -> impl Future<Output=i32>{
6	async {1}
7}

同样道理 async fn In Traits 就会脱糖到RPITIT AFIT-> RPITIT -> GAT/关联类型

RTN

https://rust-lang.github.io/rfcs/3654-return-type-notation.html#where-rtn-can-be-used-for-now 一个是where子句上面的

 1trait Foo {
 2    fn bar() -> impl Sized;
 3}
 4
 5fn is_send(_: impl Send) {}
 6
 7fn test<T>()
 8where
 9    T: Foo,
10    T::bar(..): Send,
11{
12    is_send(T::bar());
13}

在关联类型上面

 1#![feature(return_type_notation)]
 2
 3trait Foo {
 4    fn bar() -> impl Sized;
 5}
 6
 7fn is_send(_: impl Send) {}
 8
 9fn test<T>()
10where
11    T: Foo<bar(..): Send>,
12{
13    is_send(T::bar());
14}

Connect


Reference

https://nihil.cc/posts/rust_rpitit_afit/

#fact