模式匹配在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"

函数式编程之-模式匹配(Pattern matching)的更多相关文章

  1. 函数式编程之-拒绝空引用异常(Option类型)

    众多语言都会设计Option类型,例如Java 8和Swift都设计了Optional类型.其实这种类型早就出现在了函数式语言中,在OCaml和Scala中叫Option,在Haskell中叫Mayb ...

  2. Scala学习教程笔记三之函数式编程、集合操作、模式匹配、类型参数、隐式转换、Actor、

    1:Scala和Java的对比: 1.1:Scala中的函数是Java中完全没有的概念.因为Java是完全面向对象的编程语言,没有任何面向过程编程语言的特性,因此Java中的一等公民是类和对象,而且只 ...

  3. [Scala] Pattern Matching(模式匹配)

    Scala中的match, 比起以往使用的switch-case有著更強大的功能, 1. 傳統方法 def toYesOrNo(choice: Int): String = choice match ...

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

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

  5. Scala函数式编程实现排序算法

    记得<Function Thinking>这本书中提到,现在的编程范式有两类,一类是“命令式编程”,另一类是“函数式编程”,现在我们最常使用的许多语言像c.c++.java都是命令式的,但 ...

  6. 从0开发3D引擎(五):函数式编程及其在引擎中的应用

    目录 上一篇博文 函数式编程的优点与缺点 优点 缺点 为什么使用Reason语言 函数式编程学习资料 引擎中相关的函数式编程知识点 数据 不可变数据 可变数据 函数 纯函数 高阶函数 柯西化 参考资料 ...

  7. Atitit 函数式编程与命令式编程的区别attilax总结  qbf

    Atitit 函数式编程与命令式编程的区别attilax总结  qbf 1.1. 函数式程序就是一个表达式.命令式程序就是一个冯诺依曼机的指令序列. 命令式编程是面向计算机硬件的抽象,有变量(对应着存 ...

  8. Scala之模式匹配(Patterns Matching)

    前言 首先.我们要在一開始强调一件非常重要的事:Scala的模式匹配发生在但绝不仅限于发生在match case语句块中.这是Scala模式匹配之所以重要且实用的一个关键因素!我们会在文章的后半部分具 ...

  9. 用函数式编程,从0开发3D引擎和编辑器(二):函数式编程准备

    大家好,本文介绍了本系列涉及到的函数式编程的主要知识点,为正式开发做好了准备. 函数式编程的优点 1.粒度小 相比面向对象编程以类为单位,函数式编程以函数为单位,粒度更小. 正所谓: 我只想要一个香蕉 ...

随机推荐

  1. Windows 自动化补丁管理

    Windows 自动化补丁管理 Desktop Central,这一倍受欢迎的补丁管理软件旨在修补可能导致安全薄弱.破坏关键系统数据或导致系统不可用的漏洞.管理此类软件漏洞对网络管理员来说简直是噩梦. ...

  2. 别人的Linux私房菜(22)软件安装:源代码与Tarball

    执行make,会在当前目录查找makefile文本文件(记录了源代码如何编译的详细信息). 内核相关的函数信息放置在/usr/lib./usr/lib64里. 在Tarball(一般为xxx.tar. ...

  3. C++题解:Matrix Power Series ——矩阵套矩阵的矩阵加速

    Matrix Power Series r时间限制: 1 Sec 内存限制: 512 MB 题目描述 给定矩阵A,求矩阵S=A^1+A^2+--+A^k,输出矩阵,S矩阵中每个元都要模m. 数据范围: ...

  4. 高级查询query

    详细看 https://www.kancloud.cn/ldkt/tp5_db/229042

  5. spring深入学习(四)-----spring aop

    AOP概述 aop其实就是面向切面编程,举个例子,比如项目中有n个方法是对外提供http服务的,那么如果我需要对这些http服务进行响应时间的监控,按照传统的方式就是每个方法中添加相应的逻辑,但是这些 ...

  6. MySQL 多表结构的创建与分析

    =====================多对一===================== create table press( id int primary key auto_increment, ...

  7. .net HttpListener 很慢

    使用   HttpListener 做的webserver ,撒逻辑没有,内网跨机器访问,都要200ms 替换方案 EvHttpSharp.dll 使用了 libevent_core,libevent ...

  8. Breathe me

    Help, I have done it again 帮帮我,我又做错了. I have been here many times before 哪怕这已经不是一两次了. Hurt myself ag ...

  9. 如果解决小程序1024kb渲染之坑

    问题: 在小程序开发中如果有那么个场景和操作步骤,获取商品下拉列表商品列表data为goodsList 当从后台获取数据response.data.list,通常我们会setData({goodsLi ...

  10. Spring5中的DispatcherServlet初始化

    Spring MVC像许多其它Web框架,被设计围绕前端控制器(DispatcherServlet)实际的工作是由可配置的,委托组件执行提供了一种用于请求处理的共享算法.这个模型是灵活的,支持不同的工 ...