case 语句可以看作是 if/else 语法的特别版。他们的功能和作用是一样的,但有时 case 语句会令代码看起来更加清爽。考虑下面的 C#和 VB 示例。
<span>double </span>CaclRateByDate(<span>DayOfWeek </span>day) { <span>if </span>(day == <span>DayOfWeek</span>.Monday) { <span>return </span>.42; } <span>else if </span>(day == <span>DayOfWeek</span>.Tuesday) { <span>return </span>.67; } <span>else if </span>(day == <span>DayOfWeek</span>.Wednesday) { <span>return </span>.56; } <span>else if </span>(day == <span>DayOfWeek</span>.Thursday) { <span>return </span>.34; } <span>else if </span>(day == <span>DayOfWeek</span>.Friday) { <span>return </span>.78; } <span>else if </span>(day == <span>DayOfWeek</span>.Saturday) { <span>return </span>.92; } <span>else if </span>(day == <span>DayOfWeek</span>.Sunday) { <span>return </span>.18; } <span>throw new </span><span>ArgumentOutOfRangeException</span>(<span>"Unexpected enum value"</span>); }
<span>Function </span>CaclRateByDate(<span>ByVal </span>day <span>As </span>DayOfWeek) <span>As Double If </span>day = Monday <span>Then Return </span>0.42 <span>ElseIf </span>day = Tuesday <span>Then Return </span>0.67 <span>ElseIf </span>day = Wednesday <span>Then Return </span>0.56 <span>ElseIf </span>day = Thursday <span>Then Return </span>0.34 <span>ElseIf </span>day = Friday <span>Then Return </span>0.78 <span>ElseIf </span>day = Saturday <span>Then Return </span>0.92 <span>ElseIf </span>day = Sunday <span>Then Return </span>0.18 <span>Else Throw New </span>ArgumentOutOfRangeException(<span>"Unexpected enum value"</span>) <span>End If End Function</span>
开发者需要一遍又一遍地编写“ElseIf day =”或“else if (day ==”这种语句,但却并没有增加任何信息。这种语句简直就是一种折磨,不停地分散开发者的注意力,我指的是 DayOfWeek 和返回值。
在 VB 和 C#中,我们可以通过 case 语句进行简化。
<span>double </span>CaclRateByDate2(<span>DayOfWeek </span>day) { <span>switch </span>(day) { <span>case </span><span>DayOfWeek</span>.Monday: <span>return </span>.42; <span>case </span><span>DayOfWeek</span>.Tuesday: <span>return </span>.67; <span>case </span><span>DayOfWeek</span>.Wednesday: <span>return </span>.56; <span>case </span><span>DayOfWeek</span>.Thursday: <span>return </span>.34; <span>case </span><span>DayOfWeek</span>.Friday: <span>return </span>.78; <span>case </span><span>DayOfWeek</span>.Saturday: <span>return </span>.92; <span>case </span><span>DayOfWeek</span>.Sunday: <span>return </span>.18; <span>default</span>: <span>throw new </span><span>ArgumentOutOfRangeException</span>(<span>"Unexpected enum value"</span>); } }
<span>Function </span>CalcRateByDate2(<span>ByVal </span>day <span>As </span>DayOfWeek) <span>As Double Select Case </span>day <span>Case </span>Monday <span>Return </span>0.42 <span>Case </span>Tuesday <span>Return </span>0.67 <span>Case </span>Wednesday <span>Return </span>0.56 <span>Case </span>Thursday <span>Return </span>0.34 <span>Case </span>Friday <span>Return </span>0.78 <span>Case </span>Saturday <span>Return </span>0.92 <span>Case </span>Sunday <span>Return </span>0.18 <span>Case Else Throw New </span>ArgumentOutOfRangeException(<span>"Unexpected enum value"</span>) <span>End Select End Function</span>
即便如此还是有不少的重复代码。为什么总是不断地说需要一个返回值呢?像下面这样写岂不更好?
<span>double </span>CaclRateByDate2(<span>DayOfWeek </span>day) { <span>return switch </span>(day) { <span>DayOfWeek</span>.Monday: .42; <span>DayOfWeek</span>.Tuesday: .67; <span>DayOfWeek</span>.Wednesday: .56; <span>DayOfWeek</span>.Thursday: .34; <span>DayOfWeek</span>.Friday: .78; <span>DayOfWeek</span>.Saturday: .92; <span>DayOfWeek</span>.Sunday: .18; <span>default</span>: <span>throw new </span><span>ArgumentOutOfRangeException</span>(<span>"Unexpected enum value"</span>); } }
<span>Function </span>CalcRateByDate2(<span>ByVal </span>day <span>As </span>DayOfWeek) <span>As Double Return Select Case </span>day Monday: 0.42 Tuesday: 0.67 Wednesday: 0.56 Thursday: 0.34 Friday: 0.78 Saturday: 0.92 Sunday: 0.18 <span>Case Else Throw New </span>ArgumentOutOfRangeException(<span>"Unexpected enum value"</span>) <span>End Select End Function</span>
在消除了那些不必要的重复后,你会发现 C#和 VB 代码看起来是如此的接近。剩下的代码就是寻找的模式以及与模式所匹配的结果了。这就是众所周知的模式匹配。
遗憾的是,在C# 4 和VB 10 中并没有提供该特性,但却有一门新语言提供了对模式匹配的支持。看看下面这个由 Mathew Podwysocki 编写的 F#示例(需要说明的是,在下面这些示例中都创建了相应的函数)。
<span>let</span> calcRateByDay2 (day:System.DayOfWeek) = <span>match</span> day <span>with </span> | System.DayOfWeek.Monday -> 0.42 | System.DayOfWeek.Tuesday -> 0.67 | System.DayOfWeek.Wednesday -> 0.56 | System.DayOfWeek.Thursday -> 0.34 | System.DayOfWeek.Friday -> 0.78 | System.DayOfWeek.Saturday -> 0.92 | System.DayOfWeek.Sunday -> 0.18 | _ -> failwith "Unexpected enum value"
接下来 Mathew 又介绍了同时检查多个参数的方式。下面这个示例将下划线当作通配符。
<span>let</span> allowUrl url port = <span>match</span> (url, port) <span>with</span> | "http://www.microsoft.com/", 80 -> true | "http://example.com/", 8888 -> true | _, 80 -> true | _ -> false
遗憾的是,F#的语法并不简洁。如果想要操纵某个值,那就不得不通过名称或占位符来指定了。
<span>let</span> calcRateByDay3 (day:System.DayOfWeek) = <span>match</span> day <span>with </span> | x when x >= System.DayOfWeek.Monday && x <= System.DayOfWeek.Friday -> 0.42 | System.DayOfWeek.Saturday -> 0.92 | System.DayOfWeek.Sunday -> 0.18 | _ -> failwith "Unexpected enum value" <span>let</span> calcRateByDay3 (day:System.DayOfWeek) = <span>match</span> day <span>with </span> | _ when day >= System.DayOfWeek.Monday && day <= System.DayOfWeek.Friday -> 0.42 | System.DayOfWeek.Saturday -> 0.92 | System.DayOfWeek.Sunday -> 0.18 | _ -> failwith "Unexpected enum value"
下面的代码用 VB 的 case 语句实现同样的功能。
<span>Function </span>CaclRateByDate3(<span>ByVal </span>day <span>As </span>DayOfWeek) <span>As Double Select Case </span>day <span>Case </span>Monday <span>To </span>Friday : <span>Return </span>0.42 <span>Case </span>Saturday : <span>Return </span>0.92 <span>Case </span>Sunday : <span>Return </span>0.18 <span>Case Else Throw New </span>ArgumentOutOfRangeException(<span>"Unexpected enum value"</span>) <span>End Select End Function</span>
如你所见,.NET 平台上的每种语言都有自己的一些语法优势,可以将他们应用到其他语言上而无需改变语言的核心。
查看英文原文: Pattern Matching in .NET 4
评论