InfoQ

InfoQ

新闻

我的书签

登录注册 以永久保存书签。

该内容已经被标记书签!

标记书签错误,请重试!

.NET 4中的模式匹配

作者 Jonathan Allen 译者 张龙 发布于 2009年5月30日

领域
架构 & 设计,
语言 & 开发
主题
.NET ,
语言设计
标签
Visual Basic.NET ,
函数式编程 ,
F# ,
C#

case语句可以看作是if/else语法的特别版。他们的功能和作用是一样的,但有时case语句会令代码看起来更加清爽。考虑下面的C#和VB示例。

double CaclRateByDate(DayOfWeek day)
  {
      if (day == DayOfWeek.Monday)
      {
          return .42;
      }
      else if (day == DayOfWeek.Tuesday)
      {
          return .67;
      }
      else if (day == DayOfWeek.Wednesday)
      {
          return .56;
      }
      else if (day == DayOfWeek.Thursday)
      {
          return .34;
      }
      else if (day == DayOfWeek.Friday)
      {
          return .78;
      }
      else if (day == DayOfWeek.Saturday)
      {
          return .92;
      }
      else if (day == DayOfWeek.Sunday)
      {
          return .18;
      }
      throw new ArgumentOutOfRangeException("Unexpected enum value");
  }
Function CaclRateByDate(ByVal day As DayOfWeek) As Double
    If day = Monday Then
        Return 0.42
    ElseIf day = Tuesday Then
        Return 0.67
    ElseIf day = Wednesday Then
        Return 0.56
    ElseIf day = Thursday Then
        Return 0.34
    ElseIf day = Friday Then
        Return 0.78
    ElseIf day = Saturday Then
        Return 0.92
    ElseIf day = Sunday Then
        Return 0.18
    Else
        Throw New ArgumentOutOfRangeException("Unexpected enum value")
    End If
End Function

开发者需要一遍又一遍地编写“ElseIf day =”或“else if (day ==”这种语句,但却并没有增加任何信息。这种语句简直就是一种折磨,不停地分散开发者的注意力,我指的是DayOfWeek和返回值。

在VB和C#中,我们可以通过case语句进行简化。

double CaclRateByDate2(DayOfWeek day)
{
    switch (day)
    {
        case DayOfWeek.Monday:
            return .42;
        case DayOfWeek.Tuesday:
            return .67;
        case DayOfWeek.Wednesday:
            return .56;
        case DayOfWeek.Thursday:
            return .34;
        case DayOfWeek.Friday:
            return .78;
        case DayOfWeek.Saturday:
            return .92;
        case DayOfWeek.Sunday:
            return .18;
        default:
            throw new ArgumentOutOfRangeException("Unexpected enum value");
    }
}
Function CalcRateByDate2(ByVal day As DayOfWeek) As Double
    Select Case day
        Case Monday
            Return 0.42
        Case Tuesday
            Return 0.67
        Case Wednesday
            Return 0.56
        Case Thursday
            Return 0.34
        Case Friday
            Return 0.78
        Case Saturday
            Return 0.92
        Case Sunday
            Return 0.18
        Case Else
            Throw New ArgumentOutOfRangeException("Unexpected enum value")
    End Select
End Function

即便如此还是有不少的重复代码。为什么总是不断地说需要一个返回值呢?像下面这样写岂不更好?

double CaclRateByDate2(DayOfWeek day)
{
    return switch (day)
    {
        DayOfWeek.Monday: .42;
        DayOfWeek.Tuesday: .67;
        DayOfWeek.Wednesday: .56;
        DayOfWeek.Thursday: .34;
        DayOfWeek.Friday: .78;
        DayOfWeek.Saturday: .92;
        DayOfWeek.Sunday: .18;
        default:
            throw new ArgumentOutOfRangeException("Unexpected enum value");
    }
}
Function CalcRateByDate2(ByVal day As DayOfWeek) As Double
    Return Select Case day
        Monday: 0.42
        Tuesday: 0.67
        Wednesday: 0.56
        Thursday: 0.34
        Friday: 0.78
        Saturday: 0.92
        Sunday: 0.18
        Case Else
            Throw New ArgumentOutOfRangeException("Unexpected enum value")
    End Select
End Function

在消除了那些不必要的重复后,你会发现C#和VB代码看起来是如此的接近。剩下的代码就是寻找的模式以及与模式所匹配的结果了。这就是众所周知的模式匹配

遗憾的是,在C# 4和VB 10中并没有提供该特性,但却有一门新语言提供了对模式匹配的支持。看看下面这个由 Mathew Podwysocki编写的F#示例(需要说明的是,在下面这些示例中都创建了相应的函数)。

let calcRateByDay2 (day:System.DayOfWeek) = 
  match day with 
  | 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又介绍了同时检查多个参数的方式。下面这个示例将下划线当作通配符。

let allowUrl url port =
  match (url, port) with
  | "http://www.microsoft.com/", 80 -> true
  | "http://example.com/", 8888 -> true
  | _, 80 -> true
  | _ -> false

遗憾的是,F#的语法并不简洁。如果想要操纵某个值,那就不得不通过名称或占位符来指定了。

let calcRateByDay3 (day:System.DayOfWeek) = 
  match day with 
  | 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"

let calcRateByDay3 (day:System.DayOfWeek) = 
  match day with 
  | _ 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语句实现同样的功能。

Function CaclRateByDate3(ByVal day As DayOfWeek) As Double
    Select Case day
        Case Monday To Friday : Return 0.42
        Case Saturday : Return 0.92
        Case Sunday : Return 0.18
        Case Else
            Throw New ArgumentOutOfRangeException("Unexpected enum value")
    End Select
End Function

如你所见,.NET平台上的每种语言都有自己的一些语法优势,可以将他们应用到其他语言上而无需改变语言的核心。

查看英文原文:Pattern Matching in .NET 4

译者 张龙 热衷于编程,乐于分享,对新技术有强烈的探索欲,对Java轻量级框架有一定研究。

标题党 发表人 Zhao Jeffrey 发表于
标题党1 发表人 Sun Peng 发表于
标题党 发表人 Ye Ying 发表于
当年没有选择.net的原因之一 发表人 Chane Michael 发表于
Re: 当年没有选择.net的原因之一 发表人 im Kevin 发表于
最简单易懂的搞法是搞一个类似宏和元编程的玩意出来,比如可以这样搞 发表人 zhang 3 发表于
该向oracle学习了 发表人 Top Gun 发表于
Re: 该向oracle学习了 发表人 Chen Login 发表于
跟Erlang语言的模式匹配一样 发表人 li yiqun 发表于
例子举得真不好 发表人 im Kevin 发表于
  1. 返回顶部

    标题党

    发表人 Zhao Jeffrey

    F#又不是for .NET 4的。
    C# 4和VB 10根本没有模式匹配。

  2. 返回顶部

    标题党1

    发表人 Sun Peng

    说白了想函数式语言或函数式编程方式代替if或switch

    double num = (day == DayOfWeek.Monday) ? .42 :
    (day == DayOfWeek.Tuesday) ? .67 :
    (day == DayOfWeek.Wednesday) ? .56 :
    (day == DayOfWeek.Thursday) ? .34 :
    (day == DayOfWeek.Friday) ? .78 :
    (day == DayOfWeek.Saturday) ? .92 :
    (day == DayOfWeek.Sunday) ? .18 : throw new ArgumentOutOfRangeException("Unexpected enum value");

  3. 返回顶部

    标题党

    发表人 Ye Ying

    说了半天还是C# 4还是没有支持模式匹配,不过可以混合编程,应该还算不错的选择吧

  4. 返回顶部

    当年没有选择.net的原因之一

    发表人 Chane Michael

    RT,就是因为MS似乎喜欢创造很多不同的关键字/词法/语法...,应用于不同的C#,VB.NET等语言中(当然还包括其他一些原因,例如偏见)。但始终觉得,.net平台支持所谓多种编程语言,在初期可以理解为推广策略。但现在,就是累赘。

    如你所见,.NET平台上的每种语言都有自己的一些语法优势
    换言之,就是每种语言似乎都有自己的语法劣势。IMHO为什么不综合成一种更优秀的语言(哪怕是全新的),而是用支持多种编程语言,允许混合编程等方式徒增程序员负担。

  5. 返回顶部

    最简单易懂的搞法是搞一个类似宏和元编程的玩意出来,比如可以这样搞

    发表人 zhang 3

    def simplecase(switchi,cases,rts)
    casei in cases;
    rtsi in rts;
    switch(switchi)
    {
    [
    case casei: return rtsi;
    ]
    throw new ArgumentOutOfRangeException("...");
    }
    end


    使用的时候这样写就OK了:
    simplecase(day,[Monday,Tuesday,...],[0.42,0.67,... ])

  6. 返回顶部

    该向oracle学习了

    发表人 Top Gun

    Oracle中间的一个Decode就搞定了:
    DECODE(value,if1,then1,if2,then2,if3,then3,...,else),表示如果value等于if1时,DECODE函数的结果返回then1,...,如果不等于任何一个if值,则返回else。
    另外,微软应该在一门语言中集成多种优点,而不是不断创造语言来增加程序员的负担。

  7. 返回顶部

    Re: 该向oracle学习了

    发表人 Chen Login

    你这是一个函数。任何高级语言都能实现这样的函数。

  8. 返回顶部

    跟Erlang语言的模式匹配一样

    发表人 li yiqun

    .NET 4的模式匹配怎么学Erlang语言的呀

  9. 返回顶部

    Re: 当年没有选择.net的原因之一

    发表人 im Kevin

    不同意你的意见。
    全世界最优秀的程序员都在想着如何一统江湖,但是至今没有一个人能做到。百花争鸣才是未来的主流。微软不至于那么啥,又想干这种蠢事,他聪明的选择了多语言的互操作性作为未来的方向。
    至于你说的累赘,没看出来,大多数Dotnet应用,C#已经能够很好的完成了。你要出于性能考虑,你可以将其中一个组件使用另外一门语言去实现,目前哪一个平台能够做到这一点呢

  10. 返回顶部

    例子举得真不好

    发表人 im Kevin

    像这种例子,我会怎么做呢?
    如果只是简单的返回一个固定的值,那么我肯定先定义一个字典,然后查字典返回;
    如果中间会经过简单的运算,那么我会使用上述的switch-case方式,没感到什么复杂的;
    如果中间经过复杂的运算,那么我重新定义一个函数,然后使用switch-case+函数的方式实现。
    这种场景根本不是函数式编程的强项

深度内容

大规模视频网站的计费与流量管理

本次分享将会就大规模视频网站的计费与流量管理这个话题,从操作层面细细进行讲解和分析,为系统工程师们揭示平日里我们没有关心的另一些内容。同时也希望本次分享能揭示行业中的一些“潜规则”,让互联网行业的流量与带宽管理更为开放与简洁。
本次演讲视频录制于QCon杭州2011

专访Jeffrey Richter:Windows 8是微软的重中之重

Jeffrey Richter以其多本Windows核心技术的经典著作而闻名,同时,他深入掌握微软的.NET等一系列核心技术,2012年1月,Jeffrey Richter在北京接受了InfoQ中文站的专访,谈到Windows 8和WinRT编程,并就异步编程、Windows编程中的可扩展性、性能和安全性方面给出自己的建议。

应用云平台的可用性——从新浪SAE看云平台设计

云计算平台的可用性,相比传统互联网服务而言,更加复杂和困难,也更具有挑战性。本文借助新浪SAE云平台为读者讲述了云平台可用性的定义、如何打造高可用的平台,以及对云计算的用户提出了建议。

JVM定制改进 @ 淘宝

淘宝高度重视Java平台的健康发展,组建了一个团队专注于Java平台的底层部分的性能、功能与稳定性改进;工作主要基于OpenJDK中的HotSpot VM开展,其中一些通用的功能随后也会逐渐反馈给OpenJDK社区。希望能与使用Java平台开发应用的大家交流经验。
本次演讲视频录制于QCon杭州2011

"伤得起"的云计算应用——对云端应用之架构的思考

2011年4月21日至22日是值得云计算从业者纪念的日子。Amazon的IaaS服务出现故障,导致许多商业网站的服务中断,影响非常严重。作为云计算用户,我们需要思考的是,如何保证即便在云服务不可用的情况,我们的应用架构仍然能够屹立不倒?本文正是站在云计算用户的角度试图探讨这一问题。

让交付的速度跟上思考的速度

12人的技术团队,4组刀片服务器,每月20亿的访问量,每日1次准时部署,99.9%的可用性。这可能吗?当然。想知道如何做的吗?百姓网将与您分享他们在DevOps实践过程中的经验和技巧。
本次演讲视频录制于QCon杭州2011

架构之路——穿行在产品和业务之间

篱笆作为一家起源于社区的电子商务公司,反映到技术层面就是同时要面对产品和业务,以及经营战略的变化调整。如何在产品和业务的夹缝之间完成技术架构的抽象与平衡,寻找更有效的价值定位,这当中有些经验教训和个人感悟愿与众人分享。
本次演讲视频录制于QCon杭州2011

特性注入:成功三部曲

本文将对特性注入以及相关方法做一个扫盲性的介绍。我们会解释这个框架的关键要素,并附上实例来证实它们。为了让文章保持相对较短,我们不会深入到某个工具或方法中,而是会给出一些参考资料,以便大家做进一步的研究。