sea-orm是基于sqlx的ORM库(相当于MybatisPlus-Plus)。它不是此文的主角。其repo里面有一个文档介绍了它设计API时的注意点。我在此进行重新总结。
类型作为“参数” (Unit Struct)
有时候一个函数需要指定一个实现了某个trait的类型,从而使用该类型impl的函数来进行操作,以此提供更加通用的接口。
最直接的定义与调用方式是:
fn left_join<E>(self) -> Self
where
E: EntityTrait,
{
// ...
}
left_join::<MyStruct>()
但是也可以写成:
fn left_join<E>(self, _: E) -> Self
where
E: EntityTrait,
{
// ...
}
left_join(MyStruct)
这里MyStruct
是unit struct,它不包含任何数据;函数里面的对应参数也是直接丢弃。这样就能把类型当成参数一样去传递。
Builder 模式 plus
原本:
fn has_many(entity: Entity, from: Column, to: Column);
has_many(cake::Entity, cake::Column::Id, fruit::Column::CakeId)
拆解后:
has_many(cake::Entity).from(cake::Column::Id).to(fruit::Column::CakeId)
也算是一种柯里化。
简易函数重载的API优化
有时候,一个函数func1(v: Struct1)
处理Struct1
,是核心业务;但是又需要更多种类的接口,比如func2(v: Struct2)
,会对Struct2
进行预处理,变成Struct1
,然后调用func1
。由于rust不支持原生重载,因此可能会出现繁杂的函数名。
此时可以定义IntoStruct1
trait:
pub trait IntoStruct1 {
fn into_struct1(self) -> Struct1;
}
然后让Struct1
和Struct2
都impl IntoStruct1
。Struct1
单纯返回原值,而Struct2
则将原func2
中的预处理过程写入。这样就能只需要提供单一的函数func_plus
:
pub fn func_plus<A>(a: A)
where
A: IntoStruct1,
{
let a: Struct1 = a.into_struct1();
// 原func1的内容
}