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::takemem::replace

take会取出对应的数据,将Default值赋予原来的位置。这样做在一些枚举的类型转换时可以代替使用clone方法。