代码之家  ›  专栏  ›  技术社区  ›  Muhammad Alkarouri

.Net常量的F#模式匹配

  •  2
  • Muhammad Alkarouri  · 技术社区  · 15 年前

    下一个例子中的代码,

    open System.Drawing
    
    let testColor c =
        match c with
        | Color.Black -> 1
        | Color.White -> 0
        | _ -> failwith "unexpected color"
    

    不编译。错误是 Error 1 The field, constructor or member 'Black' is not defined

    如何与以大写字母开头的.Net常量或枚举进行模式匹配?

    值得一提的是,编译器是“Microsoft(R)F#2.0 Interactive build 4.0.30319.1”。

    2 回复  |  直到 15 年前
        1
  •  6
  •   Brian    15 年前

    不能对任意对象值进行模式匹配。使用 if then else when

    let testColor c = 
        match c with 
        | c when c = Color.Black -> 1 
        | c when c = Color.White -> 0 
        | _ -> failwith "unexpected color"
    
        2
  •  11
  •   Stephen Swensen    15 年前

    根据Brian的回答,模式匹配与switch语句不同。它们测试和分解输入的结构,而不是测试对象的相等性。但是,如果在整个程序中经常使用将颜色划分为黑色、白色和其他颜色,则活动模式可能是一个选项。对于一次性的“锅炉板”成本,它们允许您围绕正在操作的对象定义结构。例如,

    open System.Drawing
    let (|Black|White|Other|) (color:Color) =
        if color = Color.Black then Black
        elif color = Color.White then White
        else Other
    
    let testColor c =
        match c with
        | Black -> 1
        | White -> 0
        | Other -> failwith "unexpected color"
    

    或者,如果您同样只处理黑色和白色,但始终希望黑色的值为1,白色的值为0,则可以使用部分活动模式:

    let (|KnownColor|_|) (color:Color) =
        if color = Color.Black then Some(1)
        elif color = Color.White then Some(0)
        else None
    
    let testColor2 c =
        match c with
        | KnownColor i -> i
        | _ -> failwith "unexpected color"
    

    更一般地,您甚至可以使用通用的部分活动模式模拟switch语句:

    let (|Equals|_|) (lhs) (rhs)  =
        if lhs = rhs then Some(lhs) else None
    
    let testColor3 c =
        match c with
        | Equals Color.Black _ -> 1
        | Equals Color.White _ -> 0
        | _ -> failwith "unexpected color"
    
    let testString c =
        match c with
        | Equals "Hi" _ -> 1
        | Equals "Bye" _ -> 0
        | _ -> failwith "unexpected string"