必威体育Betway必威体育官网
当前位置:首页 > IT技术

函数式编程之-模式匹配(Pattern matching)

时间:2019-08-08 22:42:12来源:IT技术作者:seo实验室小编阅读:89次「手机版」
 

模式匹配

模式匹配的基本用法

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

1

2

3

4

match [something] with

| pattern1 -> expression1

| pattern2 -> expression2

| pattern3 -> expression3

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

考虑下面的例子:

1

2

3

4

5

let x =

match 1 with

| 1 -> "a"

| 2 -> "b"

| _ -> "z"

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

1

| _ -> "z"

通配符_在这里起到了default的作用,上面的所有分支如果都匹配失败,则最终会匹配的这个分支。

1.分支是有顺序的

但是这三个分支的顺序是可以随便改的,也就意味着我们可以把通配符分支放到第一个位置:

1

2

3

4

5

let x =

match 1 with

| _ -> "z"

| 1 -> "a"

| 2 -> "b"

在这个例子中,第一个匹配分支会胜出,同时编译器也会给出一个警告:其他的分支从来都不会被用到。

这说明在模式匹配中,分支的顺序是非常重要的,应该把更加具体的匹配分支放在前面,包含通配符的分支应该放在最后面。

2.模式匹配是一个表达式

模式匹配是一个表达式,所有的分支都应该返回同样的类型,考虑下面的例子:

1

2

3

4

5

let x =

match 1 with

| 1 -> 42

| 2 -> true // ERROR wrong type

| _ -> "hello" // error wrong type

不同的分支应该返回想通类型的值。

3.至少有一个分支能被匹配到

考虑下面的例子:

1

2

3

4

let x =

match 42 with

| 1 -> "a"

| 2 -> "b"

由于两个分支都没有匹配到,编译器将会给出警告,你至少要写一个能够匹配到的分支,例如为其添加通配符分支。

你可以通过添加通配符分支让编译器不在发出警告,但是在实际实践中,你应该尽可能的添加可能存在的分支,例如你在对一个选择类型做模式匹配:

1

2

3

4

5

6

type Choices = A | B | C

let x =

match A with

| A -> "a"

| B -> "b"

| C -> "c"

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

匹配元组(Tuple)

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

1

2

3

4

let y =

match (1,0) with

| (1,x) -> printfn "x=%A" x

| (_,x) -> printfn "other x=%A" x

显然第一个分支会被匹配到。

你可以把多个模式写在同一个分支上,当多个模式是的关系时用|隔开:

1

2

3

4

5

type Choices = A | B | C | D

let x =

match A with

| A | B | C -> "a or b or c"

| D -> "d"

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

1

2

3

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

1

2

3

4

5

6

7

8

9

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...

1

2

3

4

5

6

7

8

9

10

11

12

13

//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关键字指向另一个名称:

1

2

3

4

5

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类型:

1

2

3

4

let detectType v =

match box v with

| :? int -> printfn "this is an int"

| _ -> printfn "something else"

匹配类型并不是一种好的实践,正如你在OO语言里编写if type ==...一样。

when条件

有时候你需要对匹配完成的值做一些条件判断:

1

2

3

4

5

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条件来做到:

1

2

3

4

5

6

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

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

郑州不孕不育哪家好

郑州不孕不育哪家好

郑州男科医院哪家好

郑州好的男科医院

相关阅读

Pattern.compile函数的相关解释

Pattern.compile函数:Pattern Pattern.compile(String regex, int flag)flag的取值范围如下:Pattern.CANON_EQ:当且仅当两个字符的"

Java正则表达式Pattern和Matcher类详解

概述 Pattern类的作用在于编译正则表达式后创建一个匹配模式. Matcher类使用Pattern实例提供的模式信息对正则表达式进行匹配

完美匹配(matching)

完美匹配(matching) 题目描述 给定nn个点,mm条边的无向图G=(V,E)G=(V,E),求出它的完美匹配数量对106+3106+3取模的值。 一个完美匹

log4j的ConversionPattern参数的意义

1、常用标志:-X: X信息输出时左对齐 %p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL, %d: 输出日志时间点的日期或时间,默认格

分享到:

栏目导航

推荐阅读

热门阅读