首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >F#:使用特定类型/别名类型的经验法则?

F#:使用特定类型/别名类型的经验法则?
EN

Stack Overflow用户
提问于 2019-05-31 10:56:04
回答 2查看 75关注 0票数 1

我正在创建一种“信封”,以跟踪我在应用程序中通过RabbitMQ发送的内容(命令和事件)如下:

代码语言:javascript
复制
type Envelope<'T> = {
    Id: Guid
    CausationId: Guid
    CorrelationId: Guid
    Payload: 'T
    Timestamp: DateTimeOffset
}

'T通常是表单的命令或事件:

代码语言:javascript
复制
type Commands =
    | DoA of Stuff
    | DoB of Stuff
    | DoC of Stuff

type Events =
    | AHappened of Stuff
    | BHappened of Stuff
    | CHappened of Stuff

注意:我故意使用相对通用的名称。

但是,我也可以使用特定类型:

代码语言:javascript
复制
type CausationId = CausationId of Guid
type CorrelationId = CorrelationId of Guid
type CommandId = CommandId of Guid
type EventId = EventId of Guid
type Timestamp = Timestamp of DateTimeOffset

type DataToDoA = DataToDoA of Stuff
type DataToDoB = DataToDoB of Stuff
type DataToDoC = DataToDoC of Stuff

type Commands =
    | DoA of DataToDoA
    | DoB of DataToDoB
    | DoC of DataToDoC

type DataLeftByA = DataLeftByA of Stuff
type DataLeftByB = DataLeftByB of Stuff
type DataLeftByC = DataLeftByC of Stuff

type Events =
    | AHappened of DataLeftByA
    | BHappened of DataLeftByB
    | CHappened of DataLeftByC

这将导致:

代码语言:javascript
复制
type CommandEnvelope<`T> = {
    Id: CommandId
    CausationId: CausationId
    CorrelationId: CorrelationId
    Payload: `T
    Timestamp: Timestamp
}

type EventEnvelope<`T> = {
    Id: EventId
    CausationId: CausationId
    CorrelationId: CorrelationId
    Payload: `T
    Timestamp: Timestamp
}

有没有经验法则来决定什么时候使用这些特定的类型/别名?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-05-31 11:17:49

我不认为这是一条经验法则,但有一种系统化的思考方式是考虑是否需要在代码中单独传递由这些额外类型表示的值。如果不是,那你就不需要那些额外的类型了。如果是的话,他们可能会有用。

假设您只有Stuff,并且:

代码语言:javascript
复制
type DataLeftByA = DataLeftByA of Stuff
type DataLeftByB = DataLeftByB of Stuff

type Events =
    | AHappened of DataLeftByA
    | BHappened of DataLeftByB

这样做的一件事就是编写一个函数:

代码语言:javascript
复制
let processDataA (DataLeftByA stuff) = (...)

这个函数接受包含一些DataLeftByAStuff。但是,该类型清楚地表明,该函数只应用于由A引起的事件。以下将是类型错误:

代码语言:javascript
复制
let handleEvent = function
    | AHappened adata -> processDataA adata
    | BHappened bdata -> processDataA bdata // Type error here!

如果您将Events定义为只是连接相同Stuff的事件

代码语言:javascript
复制
type Events =
    | AHappened of Stuff
    | BHappened of Stuff

那么您的事件携带的数据是相同的,但是您正在失去定义像processDataA这样的函数的能力,因为事件A所携带的数据没有单独的类型。您可以只定义processStuff,但是可以在AB的情况下调用它。

我认为这是这两个版本之间真正有实际区别的唯一东西。因此,经验法则是-您是否需要定义像processDataA这样的函数?

票数 3
EN

Stack Overflow用户

发布于 2019-05-31 11:24:58

F#的乐趣和利润的Scott在他的“带类型的设计”系列中谈到了这一点。在关于单个案例联合类型的文章中,他解释说,使用单用例联合类型的主要原因之一是您想要添加一些验证逻辑。这使您可以进一步完善您的类型。

他举的例子是电子邮件。您可以使用type Person = { ... Email: string ... },但这不能保证字符串是电子邮件地址。为它创建一个新类型( type EmailAddress = Email of string ),那么您只能从首先验证它的函数中创建电子邮件地址。这可能是一个良好的理智检查,并有助于确保您没有分配电子邮件地址的东西不是地址/链接。

TL;DR单用例联合类型对于在代码中添加进一步的语义/验证非常有用。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56393781

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档