编者:C# 7.0也加入了模式匹配,来源于F#。


模式匹配在F#是非常普遍的,用来对某个值进行分支匹配或流程控制。

模式匹配的基本用法

模式匹配通过match...with表达式来完成,一个完整的模式表达式长下面的样子:

match [something] with
| pattern1 -> expression1
| pattern2 -> expression2
| pattern3 -> expression3

当你第一次使用模式匹配,你可以认为他就是命令式语言中的switch...case或者说是if...else if...else。只不过模式匹配的能力要比switch...case强大的多。
考虑下面的例子:

let x =
    match 1 with
    | 1 -> "a"
    | 2 -> "b" 
    | _ -> "z"

显然,x此时的值是"a",因为第一个匹配分支就匹配正确了。在这个表达式里第三个匹配分支有点特殊:

| _ -> "z"

通配符_在这里起到了default的作用,上面的所有分支如果都匹配失败,则最终会匹配的这个分支。
1.分支是有顺序的
但是这三个分支的顺序是可以随便改的,也就意味着我们可以把通配符分支放到第一个位置:

let x =
   match 1 with
   | _ -> "z"
   | 1 -> "a"
   | 2 -> "b"

在这个例子中,第一个匹配分支会胜出,同时编译器也会给出一个警告:其他的分支从来都不会被用到。
这说明在模式匹配中,分支的顺序是非常重要的,应该把更加具体的匹配分支放在前面,包含通配符的分支应该放在最后面。
2.模式匹配是一个表达式
模式匹配是一个表达式,所有的分支都应该返回同样的类型,考虑下面的例子:

let x =
    match 1 with
    | 1 -> 42
    | 2 -> true  // error wrong type
    | _ -> "hello" // error wrong type

不同的分支应该返回想通类型的值。
3.至少有一个分支能被匹配到
考虑下面的例子:

let x =
    match 42 with
    | 1 -> "a"
    | 2 -> "b"

由于两个分支都没有匹配到,编译器将会给出警告,你至少要写一个能够匹配到的分支,例如为其添加通配符分支。
你可以通过添加通配符分支让编译器不在发出警告,但是在实际实践中,你应该尽可能的添加可能存在的分支,例如你在对一个选择类型做模式匹配:

type Choices = A | B | C
let x =
    match A with
    | A -> "a"
    | B -> "b"
    | C -> "c"

如果后来某一天你在Choices类型里添加了一个新的选项D,编译器就会对之前的对Choices的模式匹配发出警告,提示你添加新的分支。试想如果你之前加了通配符,编译器就会吞掉这个警告,进而产生bug。

匹配元组(Tuple)

模式匹配几乎可以匹配F#所有的类型,例如元组:

let y =
    match (1,0) with
    | (1,x) -> printfn "x=%A" x
    | (_,x) -> printfn "other x=%A" x

显然第一个分支会被匹配到。
你可以把多个模式写在同一个分支上,当多个模式是的关系时用|隔开:

type Choices = A | B | C | D
let x =
    match A with
    | A | B | C -> "a or b or c"
    | D -> "d"

当多个模式是的关系时用&隔开:

let y =
    match (1,0) with
    | (2,x) & (_,1) -> printfn "x=%A" x

匹配list

匹配list只有三种模式:

  • [x;y;z]用来显示匹配list中的元素

  • head::tail head会匹配到第一个元素,其他的元素会匹配到tail,这个模式常用来对list做递归

  • [] 会匹配到空的list

let rec loopAndPrint aList =
    match aList with
    | [] ->
        printfn "empty"
    | x::xs ->
        printfn "element=%A," x
        loopAndPrint xs
loopAndPrint [1..5]

当[]模式被匹配到,说明list已经为空,可以作为递归的终止条件;
x::xs模式会将第一个元素匹配到x中,剩余的元素被匹配到xs,然后xs又被当做参数做下一次递归

匹配Recoard type和Descriminated Union type...

//record type
type Person = {First:string; Last:string}
let person = {First="john"; Last="doe"}
match person with
| {First="john"}  -> printfn "Matched John"
| _  -> printfn "Not John"
//union type
type IntOrBool= I of int | B of bool
let intOrBool = I 42
match intOrBool with
| I i  -> printfn "Int=%i" i
| B b  -> printfn "Bool=%b" b

其他

1.as关键字
你可以把模式用as关键字指向另一个名称:

let y =
    match (1,0) with
    | (x,y) as t ->
        printfn "x=%A and y=%A" x y
        printfn "The whole tuple is %A" t

2.匹配子类
:?用来匹配类型,例如第一个分支用来匹配int类型:

let detectType v =
    match box v with
        | :? int -> printfn "this is an int"
        | _ -> printfn "something else"

匹配类型并不是一种好的实践,正如你在OO语言里编写if type ==...一样。
when条件
有时候你需要对匹配完成的值做一些条件判断:

let elementsAreEqual aTuple =
    match aTuple with
    | (x,y) ->
        if (x=y) then printfn "both parts are the same"
        else printfn "both parts are different"

这种情况可以通过在模式中添加when条件来做到:

let elementsAreEqual aTuple =
    match aTuple with
    | (x,y) when x=y ->
        printfn "both parts are the same"
    | _ ->
        printfn "both parts are different"

Active pattern

when语句尽管可以给模式添加一些条件,但是当语句过于复杂的时候可以考虑某个分支的模式定义为一个方法:

open System.Text.RegularExpressions
// create an active pattern to match an email address
let (|EmailAddress|_|) input =
   let m = Regex.Match(input,@".+@.+")
   if (m.Success) then Some input else None 
// use the active pattern in the match 
let classifyString aString =
    match aString with
    | EmailAddress x ->
        printfn "%s is an email" x
         
    // otherwise leave alone
    | _ ->
        printfn "%s is something else" aString
//test
classifyString "alice@example.com"
classifyString "google.com"

原文地址:https://www.cnblogs.com/xiandnc/p/9388259.html

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

函数式编程之-模式匹配(Pattern matching)相关推荐

  1. 模式匹配Pattern Matching

    目录 1.模式匹配(pattern matching)的概念 2. 制造模式匹配的测试串 3. 模式匹配蛮力算法(Brute-Force,也成Naive朴素算法) 3.1 Version 1 3.2 ...

  2. Python 3.10 的新功能:模式匹配 Pattern Matching

    简介 2021 年 3 月 2 日的时候,Guido 发推说 3.10.0a6 出来了,文档也已经有了,4 月 5 日会释出 a7,5 月 3 日出 b1. 推文中还特别提到「With Pattern ...

  3. java 匿名函数_国外程序员用的火热的Vavr是什么鬼?让函数式编程更简单!

    引言 相信很多人关注 Vavr 的原因,还是因为 Hystrix 库.Hystrix 不更新了,并在 GitHub 主页上推荐了 Resilience4j,而 Vavr 作为 Resilience4j ...

  4. 让JavaScript回归函数式编程的本质

    JavaScript是一门被误会最深的语言,这话一点不假,我们看下它的发展历史. 1995年,Netscape要推向市场,需要一门脚本语言来配套它.是使用一门已有的语言,还是发明一门新的语言,这也不是 ...

  5. Functional Programming For The Rest of Us 翻译,重译 (剩人们的函数式编程)

    Functional Programming For The Rest of Us 翻译,重译 (剩人们的函数式编程) 原作者: Slava Akhmechet(译者注:这哥们不像marting fo ...

  6. Software Foundation - Coq 函数式编程 (Basics) 题解

    本书英文版地址https://softwarefoundations.cis.upenn.edu/current/index.html 本书中文版地址https://coq-zh.github.io/ ...

  7. python partition函数_如何使用正确的姿势进行高效Python函数式编程?

    演讲者:丁来强@Splunk  PyConChina2015 北京站 9月12日与9月19日,PyConChina 2015上海站与北京站顺利落下帷幕."人生苦短,Python 当歌&quo ...

  8. 《Java8实战》笔记(14):函数式编程的技巧

    函数式编程的技巧 无处不在的函数 术语"函数式编程"意指函数或者方法的行为应该像"数学函数"一样-- 没有任何副作用. 对于使用函数式语言的程序员而言,这个术语 ...

  9. Kotlin 函数式编程(Kotlin Functional Programming)

    Kotlin 函数式编程 (Kotlin Functional Programming)     陈光剑 1. 函数式概述 6 1.1. 函数式简史 6 1.2. 函数式编程语言家族 7 1.2.1. ...

最新文章

  1. 用存储过程实现数据分页
  2. Java多线程编程总结
  3. Cisco三层交换机DHCP中继简单配置
  4. python if else break_Python的for和break循环结构中使用else语句的技巧
  5. 大学4年毕业后我是如何还清的助学贷款。
  6. java学习(154):文件复制
  7. 推荐系统之 BPR 算法及 Librec的BPR算法实现【1】
  8. python教程循环语句_Python教程:关于Python 循环语句
  9. JS在html中加法器,JavaScript_JavaScript程序设计之JS调试,本文主要通过一个加法器,介 - phpStudy...
  10. Java运行原理研究(未完待续)
  11. SQL:postgresql中合并多个查询结果UNION (ALL)
  12. DATASNAP数据序列之FIREDAC的TFDJSONDataSets
  13. hexo 环境变量_优雅的博客框架,快速、简洁、高效且主题丰富——Hexo
  14. linux免杀工具,kali 免杀工具shellter安装以及使用
  15. roundcube db.inc.php,Roundcube Webmail 安装配置篇
  16. H264BSAnalyzer 使用方法
  17. 坐在家中点击鼠标,万里之外ATM吐钞……
  18. 使电动机反转的matlab仿真图,关于电机正反转电路、电机顺序启动、逆序停止的电路仿真图分析...
  19. 苹果用户在微信内打开下载链接如何不用跳转就能下载app
  20. 云服务器上传文件软件,云服务器上传文件软件

热门文章

  1. PHP中file_put_contents()函数的兼容性问题
  2. 读取数量不定的输入数据
  3. 揭秘.NET Core剪裁器背后的技术
  4. WPF DataGrid 如何将被选中行带到视野中
  5. ASP.NET Core 跨平台图形验证码实现
  6. SignalR在React/Go技术栈的实践
  7. 如何在 ASP.NET CORE 中获取客户端 IP ?
  8. C# 极限压缩 dotnet core 控制台发布文件
  9. Windows环境下Dapr入门
  10. 仓储模式到底是不是反模式?