如何写出更好的Rust API —— 阅读sea-orm Design有感

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)

这里MyStructunit 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;
}

然后让Struct1Struct2都impl IntoStruct1Struct1单纯返回原值,而Struct2则将原func2中的预处理过程写入。这样就能只需要提供单一的函数func_plus

pub fn func_plus<A>(a: A)
where
    A: IntoStruct1,
{
    let a: Struct1 = a.into_struct1();
    // 原func1的内容
}
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值