F#中用于字符串的枚举类型

6

我正在处理一个无法修改的旧数据库。由于类型提供程序,我决定使用F#。现在我已经深入其中,但事情并不那么简单。我如何为我的数据库中只有以下字符串的字段结构化呢?它有点像枚举类型。我尝试了以下方法,但还没有完全搞清楚。

尝试1

type SuspendedDriver = "SI"
type ActiveDriver = "IMPRESO"
type Applicant = "NO"
type TemporaryDriver = "TEMP"
type Uncertain = "NULL"

type DriverStatus =
    | SuspendedDriver
    | ActiveDriver
    | Applicant
    | TemporaryDriver
    | Uncertain

type Driver = {
    status : DriverStatus
    }

错误

Error FS0618: Invalid literal in type (FS0618) (ScriptTest)

第二次尝试

type DriverStatus =
    | SuspendedDriver = "SI"
    | ActiveDriver = "IMPRESO"
    | Applicant = "NO"
    | TemporaryDriver = "TEMP"
    | Uncertain = "NULL"

错误

Error FS0951: Literal enumerations must have type int, uint, int16,
uint16, int64, uint64, byte, sbyte or char (FS0951) (ScriptTest)

3
不能将字符串赋值给 union 的 case,你需要编写一个函数将 union 转换为/从字符串转换。请参考 https://dev59.com/nGEi5IYBdhLWcg3wK5nd#21559837。 - Sam
1个回答

5

正如评论中提到的,你不能定义一个被擦除为字符串的值的枚举。枚举只能是整数(不同类型的整数)。

以丑陋的方式使用枚举

可以使用枚举字段的实际名称,然后使用Enum.Parse解析它们,但这可能不是一个好主意,因为枚举案例将成为相当晦涩的代码。但为了记录,以下方法也可以:

type DriverStatus =
   | SI = 0

System.Enum.Parse(typeof<DriverStatus>, "SI") :?> DriverStatus

更清晰的解析到带差别的联合(discriminated union)中

实际上,我会像Sam建议的那样编写一个函数来解析从数据库中读取的字符串。这样做的好处是你需要决定如何处理数据库中的错误(该值可能总是有问题的):

type DriverStatus =
   | SuspendedDriver
   | ActiveDriver

let parseDriverStatus = function
   | "SI" -> SuspendedDriver
   | "IMPRESO" -> ActiveDriver 
   | code -> failwith (sprintf "Wrong driver code! %s" code)

使用酷炫的Enum SQL提供程序

最后,如果您正在使用MS SQL数据库,则SQL Command Provider项目具有一个很棒的功能,可以让您自动从SQL数据库本身导入类似枚举的类型,这可能正是您在此情况下需要的。


哇!谢谢Tomas :) 我对F#变得超级感兴趣。我已经想要玩弄类型提供程序(或只是类型)并获得更多的判别联合体。有任何资源可以提供这些内容吗?我在考虑是否有一个针对使用传统数据库或结构进行工作的F#指南,那会很好。是否有这样的资源存在? - ovatsug25

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接