新类型模式

badge

这是 Rust 中常用的 newtype 模式的 Erg 版本

Erg 允许定义类型别名如下,但它们只引用相同的类型

UserID = Int

因此,例如,如果你有一个规范,类型为 UserId 的数字必须是一个正的 8 位数字,你可以输入 10-1,因为它与类型 Int 相同 . 如果设置为 Nat,则可以拒绝 -1,但 8 位数字的性质不能仅用 Erg 的类型系统来表达

此外,例如,在设计数据库系统时,假设有几种类型的 ID: 用户 ID、产品 ID、产品 ID 和用户 ID。如果 ID 类型的数量增加,例如用户 ID、产品 ID、订单 ID 等,可能会出现将不同类型的 ID 传递给不同函数的 bug。即使用户 ID 和产品 ID 在结构上相同,但它们在语义上是不同的

对于这种情况,newtype 模式是一个很好的设计模式

UserId = Class {id = Nat}
UserId.
    new id: Nat =
        assert id.dights().len() == 8, else: "UserId 必须是长度为 8 的正数"
        UserId::__new__ {id;}

i = UserId.new(10000000)
print! i # <__main__.UserId object>
i + UserId.new(10000001) # TypeError: + is not implemented between `UserId` and `UserId

构造函数保证 8 位数字的前置条件 UserId 失去了 Nat 拥有的所有方法,所以每次都必须重新定义必要的操作 如果重新定义的成本不值得,最好使用继承。另一方面,在某些情况下,方法丢失是可取的,因此请根据情况选择适当的方法