函数式编程之-模式匹配(Pattern matching)
編者:C# 7.0也加入了模式匹配,來源于F#。
模式匹配在F#是非常普遍的,用來對(duì)某個(gè)值進(jìn)行分支匹配或流程控制。
模式匹配的基本用法
模式匹配通過match...with表達(dá)式來完成,一個(gè)完整的模式表達(dá)式長下面的樣子:
| match [something] with | pattern1 -> expression1| pattern2 -> expression2| pattern3 -> expression3 |
當(dāng)你第一次使用模式匹配,你可以認(rèn)為他就是命令式語言中的switch...case或者說是if...else if...else。只不過模式匹配的能力要比switch...case強(qiáng)大的多。
考慮下面的例子:
| let?x = ????match 1 with ????| 1 -> "a"????| 2 -> "b"?????| _ -> "z" |
顯然,x此時(shí)的值是"a",因?yàn)榈谝粋€(gè)匹配分支就匹配正確了。在這個(gè)表達(dá)式里第三個(gè)匹配分支有點(diǎn)特殊:
| | _ -> "z" |
通配符_在這里起到了default的作用,上面的所有分支如果都匹配失敗,則最終會(huì)匹配的這個(gè)分支。
1.分支是有順序的
但是這三個(gè)分支的順序是可以隨便改的,也就意味著我們可以把通配符分支放到第一個(gè)位置:
| let?x = ???match 1 with ???| _ -> "z"???| 1 -> "a"???| 2 -> "b" |
在這個(gè)例子中,第一個(gè)匹配分支會(huì)勝出,同時(shí)編譯器也會(huì)給出一個(gè)警告:其他的分支從來都不會(huì)被用到。
這說明在模式匹配中,分支的順序是非常重要的,應(yīng)該把更加具體的匹配分支放在前面,包含通配符的分支應(yīng)該放在最后面。
2.模式匹配是一個(gè)表達(dá)式
模式匹配是一個(gè)表達(dá)式,所有的分支都應(yīng)該返回同樣的類型,考慮下面的例子:
| let?x = ????match 1 with ????| 1 -> 42????| 2 -> true??// error wrong type????| _ -> "hello"?// error wrong type |
不同的分支應(yīng)該返回想通類型的值。
3.至少有一個(gè)分支能被匹配到
考慮下面的例子:
| let?x = ????match 42 with ????| 1 -> "a"????| 2 -> "b" |
由于兩個(gè)分支都沒有匹配到,編譯器將會(huì)給出警告,你至少要寫一個(gè)能夠匹配到的分支,例如為其添加通配符分支。
你可以通過添加通配符分支讓編譯器不在發(fā)出警告,但是在實(shí)際實(shí)踐中,你應(yīng)該盡可能的添加可能存在的分支,例如你在對(duì)一個(gè)選擇類型做模式匹配:
| type Choices = A | B | Clet?x = ????match A with ????| A -> "a"????| B -> "b"????| C -> "c" |
如果后來某一天你在Choices類型里添加了一個(gè)新的選項(xiàng)D,編譯器就會(huì)對(duì)之前的對(duì)Choices的模式匹配發(fā)出警告,提示你添加新的分支。試想如果你之前加了通配符,編譯器就會(huì)吞掉這個(gè)警告,進(jìn)而產(chǎn)生bug。
匹配元組(Tuple)
模式匹配幾乎可以匹配F#所有的類型,例如元組:
| let?y = ????match (1,0) with ????| (1,x) -> printfn "x=%A"?x????| (_,x) -> printfn "other x=%A"?x |
顯然第一個(gè)分支會(huì)被匹配到。
你可以把多個(gè)模式寫在同一個(gè)分支上,當(dāng)多個(gè)模式是或的關(guān)系時(shí)用|隔開:
| type Choices = A | B | C | Dlet?x = ????match A with ????| A | B | C -> "a or b or c"????| D -> "d" |
當(dāng)多個(gè)模式是與的關(guān)系時(shí)用&隔開:
| let?y = ????match (1,0) with ????| (2,x) & (_,1) -> printfn "x=%A"?x |
匹配list
匹配list只有三種模式:
[x;y;z]用來顯示匹配list中的元素
head::tail head會(huì)匹配到第一個(gè)元素,其他的元素會(huì)匹配到tail,這個(gè)模式常用來對(duì)list做遞歸
[] 會(huì)匹配到空的list
| let?rec loopAndPrint aList = ????match aList with ????| [] -> ????????printfn "empty"????| x::xs -> ????????printfn "element=%A,"?x????????loopAndPrint xs loopAndPrint [1..5] |
當(dāng)[]模式被匹配到,說明list已經(jīng)為空,可以作為遞歸的終止條件;
x::xs模式會(huì)將第一個(gè)元素匹配到x中,剩余的元素被匹配到xs,然后xs又被當(dāng)做參數(shù)做下一次遞歸
匹配Recoard type和Descriminated Union type...
| //record typetype Person = {First:string; Last:string}let?person = {First="john"; Last="doe"}match person with | {First="john"}? -> printfn "Matched John"| _? -> printfn "Not John"//union typetype IntOrBool= I of int?| B of boollet?intOrBool = I 42match intOrBool with | I i? -> printfn "Int=%i"?i| B b? -> printfn "Bool=%b"?b |
其他
1.as關(guān)鍵字
你可以把模式用as關(guān)鍵字指向另一個(gè)名稱:
| 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.匹配子類
:?用來匹配類型,例如第一個(gè)分支用來匹配int類型:
| let?detectType v =????match box v with????????| :? int?-> printfn "this is an int"????????| _ -> printfn "something else" |
匹配類型并不是一種好的實(shí)踐,正如你在OO語言里編寫if type ==...一樣。
when條件
有時(shí)候你需要對(duì)匹配完成的值做一些條件判斷:
| 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語句盡管可以給模式添加一些條件,但是當(dāng)語句過于復(fù)雜的時(shí)候可以考慮某個(gè)分支的模式定義為一個(gè)方法:
| open System.Text.RegularExpressions// create an active pattern to match an email addresslet?(|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//testclassifyString "alice@example.com"classifyString "google.com" |
原文地址:https://www.cnblogs.com/xiandnc/p/9388259.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號(hào)文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的函数式编程之-模式匹配(Pattern matching)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 树莓派3B+,我要跑.NET CORE
- 下一篇: Asp.Net Core SignalR