通过F#中的成员函数将Discriminated Union转换为基本类型

时间:2019-12-05 13:28:05

标签: f#

我具有以下带有成员函数的已区分联合,要在其中返回未装箱的类型:

type ModelData =
    | Double of double
    | UInt32 of uint32
    | UInt16 of uint16
    | Byte of byte
    | Int32 of int32
    | String of string
    | Bit of Bit
    member inline this.Value : 'a =
        match this with
        | Double x -> x
        | UInt32 x -> x
        | UInt16 x -> x
        | Byte x -> x
        | Int32 x -> x
        | String x -> x
        | Bit x -> x

错误是成员'this.Value'没有为每个分支返回相同的类型。这可能吗?

编辑#1

我有一个如下定义的数据库,它使用这种ModelData类型:

module Database =
    type Drecord =
        { Value: ModelData}
    type Db = Dictionary<string, Drecord>

所以我有一个充满值的数据库,然后使用其中一些值并使用sprintf生成JSON字符串。

sprintf "{\"General\":{\"Example\":%.3f}}" value //where value is of type ModelData

这当前不起作用,因为sprintf需要float而不是ModelData。所以原来我以为我可以调用一个函数以安全地转换为该类型(因此,this.Value成员)。我通过让this.Value代替返回一个字符串,并且在我的sprintf格式字符串中只有%s来解决这个问题。 如此有效:

sprintf "{\"General\":{\"Example\":%s}}" value.Value

是否有更好的方法来解决这个问题?

1 个答案:

答案 0 :(得分:2)

我不确定我了解您要做什么。如果定义了一个有区别的联合,则该值可以是两种情况之一,并且当您要使用ModelData类型的值时,需要对其进行模式匹配以确定哪种值你有。

如果您添加一种获取仅在特定情况下有效的值的方式(例如,当该值是float时),您将失去已区别工会提供的所有安全性。因此,我认为按照您的要求去做很可能不是一个好主意。

也就是说,您可以定义一个成员GetValue<'a>,可以使用unbox函数来调用该成员以提取特定类型的值:

type ModelData =
    | Double of double
    | UInt32 of uint32
    | UInt16 of uint16
    member inline this.GetValue<'a>() : 'a =
        match this with
        | Double x -> unbox<'a> x
        | UInt32 x -> unbox<'a> x
        | UInt16 x -> unbox<'a> x

let v = Double 1.23
v.GetValue<float>()

如果您使用错误的类型参数(例如,在上述情况下为InvalidCastException。另外请注意,这必须是一种方法,以便您可以使其通用。