成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

2009-09-09 11:37:08

Scala的模式匹配

2010-06-04 10:14:14

MySQL匹配模式

2015-01-21 16:25:29

Swift指針

2015-03-16 10:33:14

Swift指針

2015-07-08 16:43:02

Configurati

2010-07-26 10:51:26

Perl模式匹配

2010-07-26 11:02:19

Perl模式匹配

2010-07-15 17:58:31

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

字符串匹配算法

2010-07-16 09:14:49

Perl模式

2011-08-23 15:34:56

Lua模式 匹配

2010-07-21 13:27:06

Perl模式匹配

2014-02-19 10:19:12

YARA惡意軟件

2010-07-26 10:37:00

Perl模式匹配
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品av久久久久久毛片 | 国产成人福利视频在线观看 | 日韩中文字幕在线观看 | 国产亚洲精品久久久久动 | 国产精品欧美一区二区三区不卡 | 国产欧美精品一区 | 亚洲女人的天堂 | 999精品视频 | 亚洲精品91 | 国产精品波多野结衣 | 成人影院在线 | 一区二区三区精品 | 免费观看黄色一级片 | 久久噜噜噜精品国产亚洲综合 | 国产高清精品一区二区三区 | 亚洲另类视频 | 奇米av| 久久国产精品一区二区三区 | 欧美成年人视频在线观看 | 成人免费看片 | av日韩高清 | 色久伊人 | 久草资源网站 | 一级片网站视频 | 日韩一级电影免费观看 | 日韩成人高清 | 中文字幕在线网 | 99精品久久久 | 亚洲成人av在线播放 | 欧美大片一区 | 亚洲精品视频一区 | www.久久精品 | 黄色一级特级片 | 欧美日韩高清在线一区 | 日韩在线观看中文字幕 | 日韩久久精品视频 | 日韩欧美网 | 91色视频在线观看 | 国产精品乱码一区二三区小蝌蚪 | 亚洲精品亚洲人成人网 | 三级视频在线观看电影 |