1

假设我有以下有区别的联合和价值:

type DisUnion = 
    | One of string
    | Two of string
    | Three of string * string

let myVal = One("One")

我知道我可以使用模式匹配来确定myVal属于哪个案例,如下所示:

let whatever (x : DisUnion) = match x with
    | One(str) -> "It was One"
    | Two(str) - > "It was two"
    | Three(str, str) -> "It was three"

但我似乎找不到允许我在没有模式匹配的情况下确定案例标识符的运算符或方法,例如:

let isOne (x : DisUnion) = x :? One //I thought this would work, but it doesn't.

我该怎么做?任何帮助表示赞赏。

4

2 回答 2

6
let isOne = function One(_) -> true | _ -> false

Note that this is equivalent to:

let isOne x = match x with One(_) -> true | _ -> false
于 2012-06-02T11:52:48.990 回答
2

F# 中没有内置这样的运算符,但有几种不同的方法可以实现您的目标。

一种新颖的方法是通过反射,它会丢失类型检查,因此通常不会被使用。我们注意到判别联合是由 F# 编译器实现的,在您的示例中,它使用DisUnion作为基类和每个联合案例One、、TowThree作为 的子类DisUnion。因此,我们可以实现以下运算符:

let (=?) duInstance caseName = 
    let duInstanceTy = duInstance.GetType()
    duInstanceTy.Name = caseName

并像这样使用它:

> One("hi") =? "One";;
val it : bool = true
> One("hi") =? "Two";;
val it : bool = false
> One("hi") =? "NotValid";;
val it : bool = false

然而,更典型的是实现一组静态成员,DisUnion以静态类型检查的方式完成工作。实现起来有点冗长,但这是一次性成本,因为使用静态成员很好。

type DisUnion = 
    | One of string
    | Two of string
    | Three of string * string
    static member isOne x =
        match x with
        | One _ -> true
        | _ -> false
    static member isTwo x =
        match x with
        | Two _ -> true
        | _ -> false
    static member isThree x =
        match x with
        | Three _ -> true
        | _ -> false

并像这样使用它:

> DisUnion.isOne (One("hi"));;
val it : bool = true
> DisUnion.isOne (Two("hi"));;
val it : bool = false
> DisUnion.isOne (NotValid("hi"));;

  DisUnion.isOne (NotValid("hi"));;
  ----------------^^^^^^^^

C:\stdin(5,17): error FS0039: The value or constructor 'NotValid' is not defined
于 2012-06-02T14:07:24.007 回答