RUST
Published: 10/19/2023
RMETA DATA
跨crate调用
这种方法适用于若干crate需要互相调用对方的函数。如果单纯地将对方添加为依赖会导致出现循环依赖的问题,并且在某些情况下,为了确保crate之间的隔离性,也不能够直接添加依赖。
在这种情况下,可以将接口和实现分离开来,并且通过泛型的特性将需要放置在一起的方法接口放置在新的container crate中,然后在对应的实现crate中实现这些接口,就可以在container crate中调用实现crate中的方法,并且这些方法内部可以互相调用其他crate的方法而不产生循环依赖的问题。
这种方法利用到了ref-cast
库的特性,可以将一个类型转换为另一个类型,这样就可以在container crate中调用实现crate中的方法。
又或者使用linkme
第三方crate,这样通过linkme
将不同位置的方法放置在同一段中形成一个方法切片,就可以调用其中的所有方法了。
Theseus中同样提供了一种方法,通过对所有的crate生成的rlib进行解析,分别解析其中的rmeta元数据与所有组成该rlib的o目标文件,得到其依赖关系,然后加载符号表,从而实现任何函数调用。
Sized与不定长DST
Sized
是RUST中的一个特性,用于表示类型的大小是固定的,这种类型可以直接存放在栈上。而不定长DST则是指大小不固定的类型,这种类型需要通过指针来访问。
在RUST中,不定长DST的类型有str
,[T]
,Trait
等,这些类型的大小是不固定的,因此不能直接存放在栈上,而是需要通过引用来访问,对这些DST的引用称为fat pointer
,这种指针包含了指向数据的指针和数据的长度,所以是定长的。RUST使用?Sized
来表示不定长DST。
FFI
FFI
(Foreign function interface) 指的是一种语言能够调用另外一种语言编写的函数,主要利用ABI(Application Binary interface)规范来做到这一点。RUST并支持绝大部分ABI规范,其中使用最广泛的还是cdel ABI。
在RUST中,通常使用外来API都是unsafe行为,因此通常需要对原始API进行包装来提供安全和隐藏。
就cdel而言,可以使用#[repr(C)]
来修饰结构体定义使得结构体内存布局符合cdel规范,这一属性也可以用于枚举,但是实际中其实较少使用。如果C中一个函数支持可变参数,则在RUST中可以使用如下的方式来引入声明,尽管RUST本身并不支持变参函数:
extern {
fn f1(x1:u8,...);
}
RUST提供了libc
库以提供与C相关的一些内容。
RUSTFMT
自定义指令
Design Pattern
这里的所有内容都是在阅读《RUST 设计模式》时的总结。
- 借用类型的参数
定义形参时应尽可能地使用借用(如果不需要获得对应数据所有权),并且应该尽可能地让参数的覆盖范围更大。常见的例子就是使用&str
代替&String
,使用&[T]
代替&Vec<T>
,使用&T
代替&Box<T>
。
- 使用format!组建字符串
虽然书上说该方法最可读,但是也提到单纯的push
对于预分配了的字符串拼接效率可能会更高。
- Default与构造函数
RUST惯例使用关联方法new
作为类型的构造,并且如果实现了Default
trait,也会提供一个构造函数,同时为该类型提供更多的函数,比如or_default
,让代码更可读。书中同样推荐同时实现new和Default。
mem::take
与mem::replace
take
会取出对应的数据,将Default值赋予原来的位置。这样做在一些枚举的类型转换时可以代替使用clone
方法。