简体   繁体   English

在F#中,案例标识符的“是X”运算符吗?

[英]In F#, an 'is X' operator for case identifiers?

Let's say I have the following discriminated union and value: 假设我具有以下区分的并集和值:

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

let myVal = One("One")

I know I can use pattern matching to determine which case myVal belongs to, like this: 我知道我可以使用模式匹配来确定myVal属于哪种情况,如下所示:

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

But I can't seem to find an operator or method that allows me to determine the case identifier without pattern matching, like: 但是我似乎找不到能够使我无需模式匹配即可确定案例标识符的运算符或方法,例如:

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

How would I do this? 我该怎么做? Any help is appreciated. 任何帮助表示赞赏。

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

请注意,这等效于:

let isOne x = match x with One(_) -> true | _ -> false

There's no such operator built into F#, but there are a couple different approaches to achieving your goal. F#中没有内置这样的运算符,但是有两种不同的方法可以实现您的目标。

A novel approach, which loses type checking and thus wouldn't typically be used, is via reflection. 一种新颖的方法是通过反射,该方法会丢失类型检查,因此通常不会使用。 We note that discriminant unions are implement by the F# compiler using, in your example, DisUnion as a base class and each of the union cases, One , Tow , and Three as subclasses of DisUnion . 我们注意到,判别联合由F#编译器实现,在您的示例中,使用DisUnion作为基类,而每个联合案例OneTowThree作为DisUnion子类。 Thus we can implement the following operator: 因此,我们可以实现以下运算符:

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

and use it like so: 并像这样使用它:

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

More typical, however, would be to implement a set of static members on DisUnion to do the job in a statically type-checked way. 但是,更典型的做法是在DisUnion上实现一组静态成员,以通过静态类型检查的方式完成这项工作。 It's a bit verbose to implement, but it's a one time cost since using the static members is nice. 实现起来有点冗长,但是因为使用静态成员是一件很不错的事情,所以这是一次性的成本。

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

and use it like so: 并像这样使用它:

> 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM