if case
在學(xué)習(xí) if case
之前泼橘,我們先想想,那些地方使用到了case
這個(gè)關(guān)鍵字岁疼,毫無疑問,絕大多數(shù)使用case
的時(shí)候缆娃,是在 switch
語法中捷绒。
Swift
中的if case
主要用于模式匹配。跟switch
很類似贯要,但它本身有特別的使用場景暖侨,區(qū)別switch
在于,switch
用于對所有的對象可能值進(jìn)行判斷崇渗,而if case
之需要對關(guān)注的可能值進(jìn)行判斷字逗。老規(guī)矩,還是代碼上看看宅广。
假設(shè)我有一個(gè)枚舉變量CarBrand,汽車品牌葫掉。它的結(jié)構(gòu)如下:
enum CarBrand{
case BMW
case AUDI
case BENZ
}
如果使用switch
進(jìn)變量匹配,并按照不同的車的品牌輸出對應(yīng)的中文名字(這種需求當(dāng)然可以通過添加屬性值的方式更簡便的解決跟狱,但這里我們只討論if case
的使用俭厚,暫時(shí)不關(guān)注其他的方式。)驶臊。我們可能是這樣做的:
let myBrand = CarBrand.BMW
switch myBrand{
case .BMW: do{ print("寶馬") }
case .AUDI: do{ print("奧迪") }
case .BENZ: do{ print("奔馳") }
}
實(shí)際上挪挤,我們可能僅僅是想找出BMW的品牌而已叼丑,但是我卻需要寫一部分跟這個(gè)品牌無關(guān)的代碼。我們可以進(jìn)行一點(diǎn)簡化:
switch myBrand{
case .BMW: do{ print("寶馬") }
default: () // do nothing
}
可能覺得這個(gè)方式還是過于繁瑣扛门,有什么辦法可以像if
那樣對枚舉值判斷嗎鸠信?
if case
應(yīng)該能幫到你:
let myBrand = CarBrand.BMW
if case .BMW = myBrand{
print("寶馬")
}
這樣不就舒服多了,不僅沒有冗余的代碼论寨,還有具備了更好的可讀性星立。
if case let
if case let
它實(shí)際上不是一個(gè)完整的關(guān)鍵字,它if case
和let
的組合葬凳。我們同樣會在對枚舉類型進(jìn)行模式匹配的時(shí)候用到它贞铣,不過這個(gè)情況稍微復(fù)雜一點(diǎn)。
假設(shè)我的CarBrand
枚舉想要集合更多的東西沮明,比如它的中文名字和生產(chǎn)地。我們可以這樣定義這個(gè)枚舉:
enum CarBrand{
case BMW(name:String,Production:String)
case AUDI(name:String,Production:String)
case BENZ(name:String,Production:String)
}
現(xiàn)在我定一個(gè)枚舉變量:
let myCar = CarBrand.BMW(name: "寶馬",Production: "德國")
如果我想輸出myCar
的關(guān)聯(lián)屬性窍奋,直接使用點(diǎn)語法什么的都顯然是不行的荐健。我們可在枚舉中自定義一些輸出關(guān)聯(lián)屬性的方法,但是這個(gè)做法比較繁瑣琳袄,并且破壞了枚舉結(jié)構(gòu)江场。
比較簡單的是可以使用switch:
switch myCar {
case let CarBrand.BMW(name,Production):
print("This car named \(name),from\(Production)")
default: () // 不做任何處理
}
這樣確實(shí)可以的窖逗。同樣我們覺得這樣還是過于繁瑣了址否。
使用if case let
:
let myBrand = CarBrand.BMW(name: "寶馬",Production: "德國")
if case let CarBrand.BMW(name, Production) = myBrand{
print("\(name),\(Production)")
}
是不是更加簡潔呢。當(dāng)然,if case let
還可一配合where
從句寫出更加優(yōu)雅的代碼哦碎紊。
關(guān)于大于或者小于的匹配
//傳統(tǒng)用法
if x>=6 && x < 12 {
}
//模式匹配用法
if case 6..<12 = x {
}
復(fù)雜一點(diǎn)佑附,如果x是Optional對象,這里可以采用嵌套的模式匹配
//傳統(tǒng)用法
if let x = x, x>=6 && x < 12 {
}
//模式匹配用法
if case .some(6..<12) = x {
}
pattern
有很多種仗考,看一下官方文檔
GRAMMAR OF A PATTERN
pattern → wildcard-pattern
pattern → identifier-pattern
pattern → value-binding-pattern
pattern → tuple-pattern
pattern → enum-case-pattern
pattern → optional-pattern
pattern → type-casting-pattern
pattern → expression-pattern
這里不詳細(xì)介紹這些pattern
音同,更多的應(yīng)該switch
里面去學(xué)習(xí),也就是說switch
里面可以使用的在if里面都可以使用
這里舉一些例子
1. type-casting-pattern
var t : Any = 10
if case is Int = t {
print("bingo")
}
if t is Int {
}
上面兩種用法結(jié)果是一樣的秃嗜,一種是模式匹配权均,另外一種是常用的is operator
2. tuple-pattern
if case (1..<10, 1..<20) = (7, 8) {
}
在這里(1..<10, 1..<20)
是一個(gè)pattern
,而不是普通的tuple
锅锨,這里會對左右兩邊的tuple的元素一一進(jìn)行patteren match
如果把前面換成一個(gè)tuple
就會出錯(cuò)里叽赊,試試看下面的代碼
let pattern = (1..<10, 1..<20)
if case pattern = (7,8) {
}
3. optional-pattern
var t : Any? = 10
// 判斷t是不是nil,和判斷 t 必搞!= nil 等效
if case _? = t {
}
//判斷t是不是nil必指,如果有值則綁定到x
if case let x? = t {
}
4. expression-pattern
前面提到的case 6..<12 = x
實(shí)際上就是這一種pattern
,實(shí)際上這里調(diào)用了一個(gè)函數(shù)顾画,也是一個(gè)操作符~=
func ~= (pattern: String, value: Int) -> Bool {
return pattern == "\(value)"
}
if case "123" = 123 {
}
通過重載~=
操作符取劫,我們可以實(shí)現(xiàn)很多自定義的模式匹配匆笤,結(jié)合起來可以有很多有趣的用法
上面通過一些例子介紹了if中的模式匹配用法,在代碼中也有常常遇到這種用法谱邪,這種用法可以看成是switch case的一種簡易寫法炮捧,這樣理解起來就比較容易了
if case expression1 = expression2 {
statements
}
//等價(jià)于
switch expression2 {
case expression1:
statements
default:
break
}
available用法
這是一種特殊的if
用法,用來判斷運(yùn)行環(huán)境
if #available(platform name version, ..., *) {
statements to execute if the APIs are available
} else {
fallback statements to execute if the APIs are unavailable
}
這個(gè)比較簡單惦银,不再介紹
混合使用
上面四種if的使用方法可以混合使用咆课,在一個(gè)if語句中可以有多個(gè)condition
,通過,分開扯俱,這些condition
會依序執(zhí)行
var t : Any? = 10
if case let xs? = t, xs is Int {
print("bingo")
}
這里會首先將t
進(jìn)行optional-pattern
的匹配和綁定书蚪,然后判斷xs
是否是Int
condition
之前常用&&操作符進(jìn)行的判斷也可以換成使用逗號分割,效果是一樣的
最后看一下官方文檔對if
和condition list
的描述
可選類型的模式匹配
swift之模式(Pattern)
模式簡介
模式代表單個(gè)值或者復(fù)合值的結(jié)構(gòu)迅栅。比如
(10,20)
和("Tom","Mary")
在結(jié)構(gòu)上并無本質(zhì)差別殊校,都是包含兩個(gè)值的元組。swift中的模式分為兩類读存,一類能成功匹配任何類型的值为流,另一類在運(yùn)行時(shí)匹配某個(gè)特定值時(shí)可能會失敗。
第一類用于解構(gòu)簡單變量让簿、常量和可選綁定中的值敬察。包括通配符模式 和標(biāo)識符模式以及包含這兩種模式的值綁定模式和元組模式《保可以為這類模式制定一個(gè)類型標(biāo)注莲祸,從而限定他們只匹配某種特定類型的值。
第二類用于全模式匹配椭迎。锐帜,這種情況下你視圖匹配的值在運(yùn)行時(shí)可能不存在。包括枚舉用例模式畜号、可選模式抹估、表達(dá)式模式和類型轉(zhuǎn)換模式。
具體實(shí)例
- 通配符模式(Wildcard Pattern):不關(guān)注匹配的值
for _ in 1...3 {
// Do something three times
}
標(biāo)識符模式(Identifier Pattern):匹配任何值并且把匹配到的值綁定給變量或者常量弄兜。
值綁定模式(Value-Binding pattern):把匹配到的值綁定給一個(gè)變量或者常量药蜻,綁定給常量時(shí)用
let
,綁定給變量時(shí)用var
。
let point = (1,2)
switch point {
case let (x,y):
print("The point is at (\(x), \(y))") //The point is at (1, 2)
}
- 元組模式
- 逗號分隔的具有一個(gè)或者多個(gè)模式的列表
- 可以使用類型標(biāo)注去限定一個(gè)元組模式可以匹配那些元組類型替饿。
- 元組模式被用于
for-in
語句或者變量火證常量聲明時(shí)语泽,金可以包含通配符模式、標(biāo)識符模式视卢、可選模式或者其他包含這些模式的元組模式踱卵。
let points = [(0,0),(1,0),(2,0),(0,3),(1,1),(2,1)]
for (x,y) in points where y == 0 || x == 0 {
print("Point(\(x), \(y)) is on axis!")
}
for point in points {
switch point {
case (_,0), (0,_):
print("Point(\(point.0), \(point.1)) is on axis!")
default:
break
}
}
- 枚舉用例模式(Enumeration Case Pattern)
enum SomuEnum {
case left,right
}
let direction: SomuEnum? = .left
switch direction {
case .left:
print("Turn left!")
case .right:
print("Turn right!")
case nil:
print("Keep going straiht!")
}
var someOptional: Optional<Int> = 43
//枚舉用例模式匹配
switch someOptional {
case .some(let x):
print(x) // 43
case .none:
print("nil")
}
if case .some(let x) = someOptional {
print(x) // 43
}
可選項(xiàng)模式(Optional Pattern)
可選項(xiàng)模式匹配
Optional<Wrapped>
枚舉在some(Wrapped)
中包裝的值。
var someOptional: Optional<Int> = 43
if case let x? = someOptional {
print(x) // 43
}
let arrayOfOptionalInts: [Int?] = [nil,2,3,5,nil]
for case let number? in arrayOfOptionalInts {
print("Found a \(number) !")
}
類型轉(zhuǎn)換模式(Type-Casting Pattern)
is
模式:只出現(xiàn)在switch
語句的case
標(biāo)簽中,當(dāng)一個(gè)值的類型在運(yùn)行時(shí)與模式右邊指定類型一致或者是其子類的情況下才會匹配惋砂。as
模式:當(dāng)一個(gè)值的類型在運(yùn)行時(shí)和右邊指定類型一致或者是其子類的情況下妒挎,才會匹配。如果匹配成功西饵,被匹配值的類型被撞換成as
模式右邊指定的類型酝掩。
class MediaItem {
var name: String
init(name: String) {
self.name = name
}
}
class Movie: MediaItem {
var director: String
init(name: String, director: String) {
self.director = director
super.init(name: name)
}
}
class Song: MediaItem {
var artist: String
init( name: String, artist: String) {
self.artist = artist
super.init(name: name)
}
}
let library: [MediaItem] = [
Movie(name: "Casablanca", director: "Michael Curtiz"),
Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
Movie(name: "Citizen Kane", director: "Orson Welles"),
Song(name: "The One And Only", artist: "Chesney Hawkes"),
Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]
for mediaItem in library {
switch mediaItem {
case is Song :
print("Song: \(mediaItem.name)")
case let movie as Movie:
print("Movie: \(movie.name) director: \(movie.director)")
default:
break
}
}
-
表達(dá)式模式(Expression Pattern)
只出現(xiàn)在
switch
的case
標(biāo)簽中。表達(dá)式模式代表的表達(dá)式會使用Swift的標(biāo)準(zhǔn)庫中的
~=
運(yùn)算符與輸入表達(dá)式的值進(jìn)行比較眷柔,如果~=
預(yù)算內(nèi)算符返回true
,則匹配成功期虾。因此自定義類型要使用表達(dá)式模式匹配,需要重載~=
運(yùn)算符驯嘱。
let point = (0,0)
func ~= (pattern: String, value: Int) -> Bool {
return pattern == "\(value)"
}
switch point {
case ("0","0"):
print("(0,0) is at the origin.")
default:
print("The point is at (\(point.0), \(point.1))")
}