Rust 和领域驱动设计使某些错误无法编写
Rust and Domain-Driven Design to make certain errors impossible to write
我正在努力解决如何在 Rust 中实现一些在 TypeScript 中非常简单的东西。本质上是一种 sum 类型的产品类型,在编译时执行业务规则。
假设我有一个结构 Location
,它包含两个属性,state
和 city
,其中 state: StateEnum
和 city: String
。
一般来说,city
和state
分别可以容纳任何StateEnum
/String
。到目前为止,还不错:
struct Location {
state: StateEnum,
city: String,
}
但是,有些业务规则使得 state
的某些值限制了某些 city
的有效性。显然你不能有一个有效的 Location { state: StateEnum::TX, city: "New York City }
.
在 OOP 中,您可以将 city
设为私有并让 setCity
检查并抛出异常,如果该城市对于该州执行业务规则不合法。 运行时间异常。
在 FP 中,您可以编写自己的类型,因此类似于
type NYLocation = {
state: NY
city: 'Albany' | 'NYC' ...
}
type TexasLocation = { ... }
type Location = NYLocation | TexasLocation | ...
和你的 IDE 会警告你不能将 TexasLocation.city 设置为 newCity: string
除非先在代码中使用类型保护来缩小 string
的可能值至 'Houston' | 'Austin' | ...
.
有没有办法(我的意思是,显然必须有办法;是否有 惯用的 方法在 Rust 中而不是 运行-像 OOP 一样的时间?
在某种程度上,是的。您可以使用枚举静态地强制执行离散值域,就像您已经对状态所做的那样。你只需要将这个概念扩展到城市。
您可以为每个州的城市创建一个枚举,然后让 Location
成为一个枚举。
enum NewYorkCities {
Albany,
NewYorkCity,
// ...
}
enum WashingtonCities {
Seattle,
Olympia,
// ...
}
enum Location {
NewYork(NewYorkCities),
Washington(WashingtonCities),
// ...
}
这使您能够证明不在给定域中的值不能存在于程序中。
最后,您只需要一种将每个枚举与字符串相互转换的方法。这些类型的函数可以由 strum
crate 中的宏生成。
显然这需要重新编译以更改可接受的域,但无论如何您都会遇到与 TypeScript 代码相同的问题,所以我认为这是一个可以接受的缺点。
我正在努力解决如何在 Rust 中实现一些在 TypeScript 中非常简单的东西。本质上是一种 sum 类型的产品类型,在编译时执行业务规则。
假设我有一个结构 Location
,它包含两个属性,state
和 city
,其中 state: StateEnum
和 city: String
。
一般来说,city
和state
分别可以容纳任何StateEnum
/String
。到目前为止,还不错:
struct Location {
state: StateEnum,
city: String,
}
但是,有些业务规则使得 state
的某些值限制了某些 city
的有效性。显然你不能有一个有效的 Location { state: StateEnum::TX, city: "New York City }
.
在 OOP 中,您可以将 city
设为私有并让 setCity
检查并抛出异常,如果该城市对于该州执行业务规则不合法。 运行时间异常。
在 FP 中,您可以编写自己的类型,因此类似于
type NYLocation = {
state: NY
city: 'Albany' | 'NYC' ...
}
type TexasLocation = { ... }
type Location = NYLocation | TexasLocation | ...
和你的 IDE 会警告你不能将 TexasLocation.city 设置为 newCity: string
除非先在代码中使用类型保护来缩小 string
的可能值至 'Houston' | 'Austin' | ...
.
有没有办法(我的意思是,显然必须有办法;是否有 惯用的 方法在 Rust 中而不是 运行-像 OOP 一样的时间?
在某种程度上,是的。您可以使用枚举静态地强制执行离散值域,就像您已经对状态所做的那样。你只需要将这个概念扩展到城市。
您可以为每个州的城市创建一个枚举,然后让 Location
成为一个枚举。
enum NewYorkCities {
Albany,
NewYorkCity,
// ...
}
enum WashingtonCities {
Seattle,
Olympia,
// ...
}
enum Location {
NewYork(NewYorkCities),
Washington(WashingtonCities),
// ...
}
这使您能够证明不在给定域中的值不能存在于程序中。
最后,您只需要一种将每个枚举与字符串相互转换的方法。这些类型的函数可以由 strum
crate 中的宏生成。
显然这需要重新编译以更改可接受的域,但无论如何您都会遇到与 TypeScript 代码相同的问题,所以我认为这是一个可以接受的缺点。