国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Swift中的模式匹配

移動開發 iOS
例如,假設你想判斷一個整數是大于、小于還是等于零,你可以用if-else if-else語句,盡管這并不美觀:

[[156836]]

Swift有一個很好的特性,那就是模式匹配的擴展。模式是用于匹配的規則值,如switch語句的case,do語句的catch子句,以及if、while、guard、for-in語句的條件。

例如,假設你想判斷一個整數是大于、小于還是等于零,你可以用if-else if-else語句,盡管這并不美觀:

  1. let x = 10 
  2. if x > 0 { 
  3. print("大于零"
  4. else if x < 0 { 
  5. print("小于零"
  6. else { 
  7. print("等于零"

用switch語句會好很多,我理想的代碼是這樣:

  1. // 偽代碼 
  2. switch x { 
  3. case > 0
  4. print("大于零"
  5. case < 0
  6. print("小于零"
  7. case 0
  8. print("等于零"

但模式匹配默認并不支持不等式。讓我們看看能不能改變這個現狀。為了使過程更加清晰,我先忽略>0的情況,用greaterThan(0)來代替它,過后我再來定義這個操作符。

擴展模式匹配

Swift的模式匹配是基于~=操作符的,如果表達式的~=值返回true則匹配成功。標準庫自帶四個~=操作符的重載:一個用于Equatable,一個用于Optional,一個用于Range,一個用于Interval。這些都不符合我們的需求,盡管Range和Interval很接近了,關于它們你可以看這篇文章。

所以我們要實現我們自己的~=。這個方法的原型是:

  1. func ~=(pattern: ???, value: ???) -> Bool 

我們知道這個方法必須返回一個Bool,那正是我們需要的,我們需要知道這個值是否匹配模式。接下來要問我們自己的是:參數的類型是什么?

對于值,我們可以使用Int,這正是我們在之前的例子中需要的。但讓我們把它一般化,讓它能夠接受任何類型。在我們的情況里,模式形如greaterThan(001.png)或lessThan(001.png)。更一般化,模式應該是一個方法,一個能夠將值作為參數并返回true或false的方法。值的類型為T,所以模式的類型應為T -> Bool:

  1. func ~=(pattern: T -> Bool, value: T) -> Bool { 
  2. return pattern(value) 

現在我們需定義方法greaterThan和lessThan來創建模式。注意不要把模式greaterThan(0)中的0和我們想匹配的值混淆了。greaterThan的參數是模式的一部分,這個部分將在第二步中用到。舉個例子,greaterThan(0) ~= x和greaterThan(0)(x)是一樣的。

我們知道方法greaterThan(0)必須返回一個方法,這個方法要能接受一個值并返回Bool。所以greaterThan必須是一個方法,接受另一個值并返回之前方法。我們把參數限制成Comparable,為了能在實現中用Swift的>和<操作符:

  1. func greaterThan(a: T) -> (T -> Bool) { 
  2. return { (b: T) -> Bool in b > a } 

這個方法接受一個參數,調用接受不止一個參數的方法并返回,像這樣的方法這被稱為Curried functions。(Swift的部分實例方法就是一種Curried functions)Swift提供了一種特別的語法用于Curried functions,正如它們的名字一樣形象。使用這種語法,我們的方法變成了這樣:

  1. func greaterThan(a: T)(_ b: T) -> Bool { 
  2. return b > a 
  3. func lessThan(a: T)(_ b: T) -> Bool { 
  4. return b < a 

這樣我們有了***個版本的switch語句:

  1. switch x { 
  2. case greaterThan(0): 
  3. print("大于零"
  4. case lessThan(0): 
  5. print("小于零"
  6. case 0
  7. print("等于零"
  8. default
  9. fatalError("不會發生"

很不錯,但看看default,這個解決方案不能給編譯器任何提示進行完整性檢查,所以我們不得不提供一個default。如果你確定模式覆蓋了每一個可能的值,在default下調用fatalError()是一個不錯的主意,這表明這段代碼絕對不會執行到。

自定義操作符

回想一開始的想法,以及那段偽代碼。理想情況下,我們想用>0和<0取代greaterThan(0)和lessThan(0)。

自定義操作符存在爭議,因為其他讀者經常不熟悉這些,它們降低了可讀性。回到我們的例子中,類似greaterThan(0)則是完全可讀,所以完全可以認為不需要自定義操作符。但同時,每個人都知道>0意味著什么。所以讓我們來嘗試一下,但正如我們將看到的,它不會很漂亮。

我們自定義的操作符是一元的——它們只有一個操作數。同時,它們是前置操作符(而不是后置,那種操作符在操作數后的)。在一元操作符和操作數之間不能有空格,因為Swift用空格來區分一元和二元操作符。此外,<不允許用作前置操作符,我們只好用別的東西代替。(>允許前置,但不是允許后置)。

我建議我們使用~>和~<。雖然~>只是非常像箭頭并不理想,但波浪號暗示了模式匹配操作符~=。其他我可以想出的操作符(如>>和<<)則容易造成混淆。

9月25日更新:我從Nate Cook那了解到操作符~>在標準庫中已經存在。雖然它的實現都沒有公有,但Nate發現它是用來增加集合的索引。鑒于此,為一個完全不同的目的而使用相同的操作符可能不是一個好主意。你可以選個別的。

真正的實現并不重要。我們要做的就只是聲明操作符和實現方法,這些只是我們已有的方法greaterThan和lessThan的委托:

  1. prefix operator ~> { } 
  2. prefix operator ~< { } 
  3. prefix func ~>(a: T)(_ b: T) -> Bool { 
  4. return greaterThan(a)(b) 
  5. prefix func ~ Bool { 
  6. return lessThan(a)(b) 

這樣,我們的switch語句變成:

  1. switch x { 
  2. case ~>0
  3. print("大于零"
  4. case ~<0
  5. print("小于零"
  6. case 0
  7. print("等于零"
  8. default
  9. fatalError("不會發生"

再次提醒,操作符和操作數之間沒有空格。

這樣已是我們的極限,很接近原始計劃,但顯然并不***。

9月19日更新:Joseph Lord提醒我,Swift有一個類似的語法:

  1. switch x { 
  2. case _ where x > 0
  3. print("大于零"
  4. case _ where x < 0
  5. print("小于零"
  6. case 0
  7. print("等于零"
  8. default
  9. fatalError("不會發生"

這個語法,雖然它可能不像我們定制的解決方案那么簡潔,但絕對足夠好,因為你不應該為這么一個簡單的目的此創建一個自定義語法。然而,我們的解決方案是一般化的,能在不同的地方應用。繼續往下看。

其他應用

順便說一句,這里給出的解決方案是非常一般化的。我們重載的模式匹配操作符~=適用任何T類型和任何接受T類型返回Bool的方法。換句話說,我們的實現使得pattern ~= value和pattern(value)一樣好用。更進一步,switch value { case pattern: ... }和 if pattern(value) { ... }一樣好用。

檢查數字奇偶性

舉幾個例子。首先,一個簡單的例子說明了其可應用性,雖然其實際意義不大。假設你有一個方法isEven用來檢查數數字是不是偶數:

  1. func isEven(a: T) -> Bool { 
  2. return a % 2 == 0 

現在:

  1. switch isEven(x) { 
  2. case true: print("偶數"
  3. case false: print("奇數"

可以變成:

  1. switch x { 
  2. case isEven: print("偶數"
  3. default: print("奇數"

注意default,下面的代碼無效:

  1. switch x { 
  2. case isEven: print("偶數"
  3. case isOdd: print("奇數"
  4. // error: Switch must be exhaustive, consider adding a default clause 

匹配字符串

舉一個更實際的例子,假設你想要匹配一個字符串的前綴或后綴。我們先寫兩個方法hasPrefix和hasSuffix,它們接受兩個字符串,并檢查***個參數是否是第二個參數的前綴/后綴。這些只是現有標準庫中String.hasPrefix和String.hasSuffix方法的變形,只是使參數有一個方便的順序(前綴/后綴***,完整的字符串第二)。如果你經常使用Partial Applied Function(偏應用方法,缺少部分參數的方法)并將它們傳遞給其他方法,你會發現你常常需要重復出現參數來符合被調用方法的參數。煩人,但這不難。

  1. func hasPrefix(prefix: String)(value: String) -> Bool { 
  2. return value.hasPrefix(prefix) 
  3. func hasSuffix(suffix: String)(value: String) -> Bool { 
  4. return value.hasSuffix(suffix) 

現在我們可以這樣,在我看來這很容易閱讀了:

  1. let str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
  2. switch str { 
  3. case hasPrefix("B"), hasPrefix("C"): 
  4. print("以B或C開頭"
  5. case hasPrefix("D"): 
  6. print("以D開頭"
  7. case hasSuffix("Z"): 
  8. print("以Z結尾"
  9. default
  10. print("其他情況"

結論

為了解決我們最初的問題,我們提出了一個一般化的解決方案,它可以解決很多不同的問題。我發現這種情況經常發生,當你將方法看作值來傳遞,它可以用在你通常想不到的地方。這是函數式編程改進可組合性這一說法背后的核心概念之一。

擴展Swift的模式匹配系統,使其有了新的功能,無論是對于內置類型還是自定義類型,都是極其強大的。一如既往,注意不要把它擴展太多。即使一個自定義的語法看上去比保守的解決方案更為干凈,但對于那些不熟悉它的人它使代碼更加難讀了。

責任編輯:chenqingxiang 來源: CocoaChina
相關推薦

2022-08-29 15:26:58

MySQLSQL模式

2023-10-30 10:20:45

2010-07-21 13:35:22

Perl模式匹配

2010-06-04 10:14:14

MySQL匹配模式

2009-09-09 11:37:08

Scala的模式匹配

2015-07-08 16:43:02

Configurati

2015-03-16 10:33:14

Swift指針

2015-01-21 16:25:29

Swift指針

2010-07-26 11:02:19

Perl模式匹配

2010-07-15 17:58:31

Perl模式

2010-07-26 10:51:26

Perl模式匹配

2023-11-28 13:20:00

Rust匹配枚舉

2022-05-11 09:01:54

Swift類型系統幻象類型

2022-07-04 08:54:39

Swift處理器項目

2023-04-11 08:54:57

字符串匹配算法

2011-08-23 15:34:56

Lua模式 匹配

2010-07-16 09:14:49

Perl模式

2010-07-21 13:27:06

Perl模式匹配

2010-07-26 10:37:00

Perl模式匹配

2014-02-19 10:19:12

YARA惡意軟件
點贊
收藏

51CTO技術棧公眾號

成人在线观看毛片| 免费毛片小视频| av在线免费观看网| 国产亚洲字幕| 欧美极品美女视频| 日韩av在线免费看| av天天av| 国产一区清纯| 精品成人在线观看| 人妻激情另类乱人伦人妻| 黑人巨大亚洲一区二区久| 国产精品欧美一区二区三区| 免费一级特黄毛片| 琪琪一区二区三区| 水蜜桃亚洲精品| 欧美日本成人| 亚洲超丰满肉感bbw| 日韩性感在线| 亚洲精品一二三**| 欧美午夜片欧美片在线观看| 亚洲直播在线一区| 国内一区二区三区在线视频| 欧美福利网站| 国产精品123| 亚洲xxx自由成熟| 蜜桃精品噜噜噜成人av| 欧美精选在线播放| 色多多视频在线观看| 午夜不卡av在线| 日本免费高清视频| 成人18视频在线播放| 国产精品亚洲不卡a| 秋霞国产精品| 国产精品久久久久久亚洲毛片| 国产精品免费成人| 青青草91视频| 欧美一区2区三区4区公司二百| 精品一区二区三| 久久精品国产亚洲精品2020| 亚洲熟妇av日韩熟妇在线| 91影院在线免费观看| 精品人妻大屁股白浆无码| 韩国av一区二区三区四区| 国产日韩在线观看av| porn亚洲| 欧美精品一区二区三区蜜桃| 老司机在线视频二区| 欧美性感一类影片在线播放| jizzjizzji欧美| 久久国产精品一区二区| 亚欧在线免费观看| 精品国产31久久久久久| 国产粉嫩一区二区三区在线观看| 亚洲国产精品综合小说图片区| 国产精品无码av无码| 成人女性视频| 国产欧美一区二区三区视频 | 熟妇人妻无乱码中文字幕真矢织江| 国产东北露脸精品视频| 青青在线视频观看| 99久久99精品久久久久久| 亚洲欧洲精品在线| 日韩高清在线一区| 成人黄色免费电影| 欧美二区在线观看| 色猫猫成人app| 国产专区精品视频| 亚洲欧洲中文字幕| 欧美富婆性猛交| 久草热8精品视频在线观看| 国产一区二区三区小说| 久久综合久久99| 欧美日韩在线精品一区二区三区激情综 | 日本一本中文字幕| 亚洲日本va午夜在线影院| 日本在线免费| 欧美精品videossex性护士| 欧美色图麻豆| 国产爆乳无码一区二区麻豆| 一区二区三区四区五区视频在线观看| 韩国女主播一区二区三区| 国产精品国三级国产av| 色婷婷综合久色| 波多野结衣久久| 97在线观看免费| 国产精品久久久久久亚洲毛片 | 青青青草网站免费视频在线观看| 欧美日韩美女视频| 欧美人与性动交xxⅹxx| 99999精品视频| 日韩av网站电影| 成人一二三区| 免费看国产一级片| 欧美日韩一区二区三区四区 | 亚洲国产一成人久久精品| caoporn97在线视频| 国产精品私拍pans大尺度在线| 国内精品久久久久影院色| 又黄又爽无遮挡| 中文字幕剧情在线观看一区| 在线观看视频一区二区欧美日韩| 久久男人av| 亚洲资源视频| 亚洲午夜成aⅴ人片| 久久福利在线| 欧洲亚洲免费视频| 91黄色免费网站| 蜜臀av性久久久久蜜臀aⅴ四虎| 91福利精品在线观看| 999在线免费视频| 97se国产在线视频| 亚洲欧美日韩精品久久| 亚洲午夜久久久| 日本vs亚洲vs韩国一区三区| 巨人精品**| 国产盗摄在线视频网站| 成人亚洲在线观看| 精品国产伦一区二区三区观看说明| 成人福利视频在| 日韩久久久久久久| 亚洲成a人v欧美综合天堂| 亚洲aa在线| 日本 片 成人 在线| 久久不射热爱视频精品| 国产网站一区二区三区| 激情久久一区二区| 成年人黄色电影| 亚洲国产精品毛片av不卡在线| 97精品国产97久久久久久| 91黄色免费网站| 粉嫩欧美一区二区三区高清影视 | 久久国产乱子伦免费精品| 国产精品一区视频| 91在线视频九色| 国产一区二区三区中文| 欧美视频在线一区| 久久久不卡影院| 另类的小说在线视频另类成人小视频在线| 91成人精品观看| 在线heyzo| 日本中文字幕电影| 大肉大捧一进一出好爽视频| 亚洲va韩国va欧美va精四季| 欧美肥老妇视频| 精品国产免费一区二区三区四区| 欧美日韩在线影院| 久久麻豆一区二区| 日韩极品在线观看| 国产精品三级| xxxxx.日韩| 好久没做在线观看| 黄色片视频在线观看| av电影免费在线观看| 97影视大全免费追剧大全在线观看| 青青青国产在线观看| 久久亚洲一区二区| 91国产丝袜在线放| 国产精品国产三级国产aⅴ9色| 日韩在线视频观看正片免费网站| 91黄色免费版| 樱花草国产18久久久久| 中文字幕精品综合| 国产精品一区二区在线观看不卡| 免费在线播放第一区高清av| 国产精品色哟哟| 亚洲黄色录像片| 日韩毛片一二三区| 在线观看一区二区精品视频| 欧美激情国产精品| 4438全国成人免费| 日本久久久久久久| 日韩免费av片在线观看| 国产精品伊人日日| 国产精品1区2区在线观看| 91亚色免费| 蜜臀av免费观看| 99爱视频在线| 中文在线√天堂| 国产黄a三级三级三级av在线看 | 国产69精品久久久| 久久久噜噜噜久久久| 国产精品视频精品| 日本公妇乱淫免费视频一区三区| www成人免费视频| 理论片在线观看理伦片| 成人性生交大片免费看午夜| 粉嫩一区二区| 亚洲黄色一区| 蜜臀av一区二区| 亚洲精品视频免费观看| 亚洲精品中文字幕av| xx视频.9999.com| 欧美日韩成人网| 亚洲va欧美va在线观看| 91成人在线视频观看| 成人动漫av| 国偷自产一区二区免费视频| 欧美美女啪啪| www..com久久爱| 日韩欧美在线播放|