Swift 5.1 之類型轉(zhuǎn)換與模式匹配的教程詳解
類型轉(zhuǎn)換在Swift中使用 is
和 as
操作符實現(xiàn)。
類型檢查
使用操作符 is
檢查一個實例是否是某個確定的類以及其繼承體系的父類或子類類型。如果是某個確定的類(該類繼承體系的父類或子類)類型,則返回 true
,否則返回 false
。
class Cat { func hairColor() -> String { return "五顏六色" } } class WhiteCat: Cat { override func hairColor() -> String { return "白色" } } class BlackCat: Cat { override func hairColor() -> String { return "黑色" } } //必須符合`Cat`類以及其子類,類型推斷需要 let kinds = [WhiteCat(),BlackCat(),WhiteCat(),WhiteCat()] for item in kinds { if item is WhiteCat { print("白貓")//!< 3次 } if item is BlackCat { print("黑貓")//!< 1次 } if item is Cat { print("貓")//!< 4次 } }
向下轉(zhuǎn)換
某個類類型的常量或變量實際上可能是其子類的實例。這種情況下,我們會用到類型轉(zhuǎn)換操作符( as?
或 as!
)向下轉(zhuǎn)換為子類類型。
as?
:類型轉(zhuǎn)換的條件形式,向下轉(zhuǎn)換為某個類型時,返回該類型的可選值,即:轉(zhuǎn)換失敗時返回 nil
。使用場景:向下轉(zhuǎn)換可能會失敗的情況。
as!
:類型轉(zhuǎn)換的強制形式,向下轉(zhuǎn)換為某個類型時,會進行強制解包,即:轉(zhuǎn)換失敗時觸發(fā)運行時錯誤。使用場景:向下轉(zhuǎn)換確定不會失敗
//必須符合`Cat`類以及其子類,類型推斷需要 let kinds = [WhiteCat(),BlackCat(),WhiteCat(),WhiteCat()] for item in kinds { if let white = item as? WhiteCat { print("毛發(fā):\(white.hairColor())") } if let black = item as? BlackCat { print("毛發(fā):\(black.hairColor())") } }
下述內(nèi)容總結(jié)自 蘋果官方博客:
Swift 1.2之前 as
運算符可以執(zhí)行兩種不同類型的轉(zhuǎn)換:保證轉(zhuǎn)換和強制轉(zhuǎn)換。
保證轉(zhuǎn)換:保證將一種類型的值轉(zhuǎn)換為另一種類型,這種保證由編譯器編譯時驗證。
例如:
• 向上轉(zhuǎn)換(Upcasting),將當前類型的值轉(zhuǎn)換為該類型的父類之一。
• 指定數(shù)字的類型: let num = 6 as Float
**強制轉(zhuǎn)換:**強制將一種類型的值轉(zhuǎn)換為另一種類型,這種轉(zhuǎn)換編譯器無法保證安全性,并且可能觸發(fā)運行時錯誤。
例如:上述的向下轉(zhuǎn)換(Downcasting),將一種類型的值轉(zhuǎn)換為其子類之一。 在Swift 1.2之后保證轉(zhuǎn)換仍然使用 as
操作符,但強制轉(zhuǎn)換使用 as!
操作符。
Any
和 AnyObject
的類型轉(zhuǎn)換
Swift提供了兩種特殊類型來處理非特定類型:
any
AnyObject
在某些使用 any
和 AnyObject
的特殊場景下,對于 Any
和 AnyObject
表示的實例,需要運用類型轉(zhuǎn)換模式,值綁定模式,表達式模式等模式匹配的知識。所以我們先介紹下Swift中的模式。
類型轉(zhuǎn)換模式
類型轉(zhuǎn)換有兩種模式: is
模式和 as
模式。 is
模式僅在 switch
語句的 case
標簽中使用。 is
模式和 as
模式有如下形式:
is <#Type#> //pattern:代表此處也需要一個模式 <#pattern#> as <#Type#>
is 模式: 如果運行時值的類型與 is 模式右側(cè)指定的類型或該類型的子類相同,則 is 模式會匹配到這個值。此行為很適用 switch 語句的 case 場景。 is 模式的行為類似于 is 運算符,因為它們都執(zhí)行類型轉(zhuǎn)換但類型轉(zhuǎn)換后丟棄了返回的類型。
as 模式: 如果在運行時值的類型與 as 模式右側(cè)指定的類型或該類型的子類相同,則 as 模式會匹配到這個值。如果匹配成功,則會將匹配到的值的類型將轉(zhuǎn)換為 as 模式右側(cè)指定的類型。
值綁定模式
值綁定模式將匹配到的值綁定到變量或常量。 將匹配到的值綁定到常量,綁定模式以let關(guān)鍵字開頭;綁定到變量以var關(guān)鍵字開頭。
let point = (3,2) switch point { case let(x,y): //值綁定模式匹配到的X值:3,Y值:2 print("值綁定模式匹配到的X值:\(x),Y值:\(y)") }
通配符模式
通配符模式匹配并忽略任何值,并由下劃線 _ 表示。
for _ in 1...9 { print("通配符模式") }
標識符模式
標識符模式匹配任何值,并將匹配的值綁定到變量或常量的名稱。
let someValue = 42
someValue 是一個與 Int 類型的值 42 匹配的標識符模式。匹配成功, 42 將被賦值給常量 someValue 。 當變量或常量聲明的左側(cè)的模式是標識符模式時,標識符模式隱式地是值綁定模式的子模式。 ####元組模式 元組模式是以逗號分隔的零個或多個元素列表,括在括號中。元組模式匹配相應(yīng)元組類型的值。
包含單個元素的元組模式周圍的括號無效。該模式匹配該單個元素類型的值。所以下面寫法是等效的:
let a = 2 // a: Int = 2 let (a) = 2 // a: Int = 2 let (a): Int = 2 // a: Int = 2
枚舉 Case 模式
枚舉 Case 模式匹配現(xiàn)有枚舉中存在 case 。枚舉 Case 模式出現(xiàn)在 switch 語句的case標簽中以及 if , while , guard , for - in 語句中。
如果嘗試匹配的枚舉 case 具有關(guān)聯(lián)值,則相應(yīng)的枚舉 Case 模式必須指定與每個關(guān)聯(lián)值對應(yīng)的元組。
enum VendingMachineError { case InvalidGoods//!< 商品無效 case StockInsufficient//!< 庫存不足 case CoinInsufficient(coinNeeded:Int,caseDes:String) } let enumArray = [VendingMachineType.CoinInsufficient(coinNeeded: 4, caseDes: "自動售貨機,硬幣不足,請補充"), .InvalidGoods, .StockInsufficient, .CoinInsufficient(coinNeeded: 6, caseDes: "自動售貨機,硬幣不足,超過限額")] for patternCase in enumArray { switch patternCase { case .CoinInsufficient(coinNeeded: let x, caseDes: let y) where x > 5: print(x,y) case let .CoinInsufficient(coinNeeded: x, caseDes: y): print(x,y) case .InvalidGoods: print("商品無效") default: print("未匹配到") } }
枚舉 Case 模式還匹配枚舉類型的可選項。當可選項 Optional 是枚舉類型時, .none 和 .some 能夠作為枚舉類型的其他 case 出現(xiàn)在同一個 switch 語句中。這種簡化的語法允許我們省略可選模式。
enum SomeEnum { case left, right,top,down} let array : Array<SomeEnum?> = [.left,nil,.right,.top,.down] //方式一: array.forEach { (item) in switch item { case .left?: print("左") case SomeEnum.right?: print("右") case .down?: print("下") case .top?: print("上") default: print("沒有值") } } //方式二: array.forEach { (item) in switch item { case .some(let x): print("對可選項item進行解包得到:\(x)")//!< left,right,top,down case .none: print("沒有值") //nil } }
可選模式
可選模式匹配包含在 Optional<Wrapped> 枚舉(這是可選項的實現(xiàn)原理)對應(yīng)的 case 項: some(Wrapped) 中的值。即匹配可選項有值的情況。
public enum Optional<Wrapped> : ExpressibleByNilLiteral { /// The absence of a value. /// In code, the absence of a value is typically written using the `nil` /// literal rather than the explicit `.none` enumeration case. case none /// The presence of a value, stored as `Wrapped`. case some(Wrapped) ...... }
可選模式由標識符模式組成后面緊跟 ? 并出現(xiàn)在與枚舉 Case 模式相同的位置。 因為可選模式是 Optional<Wrapped> 枚舉的 Case 模式語法糖。所以下面兩種寫法是等效的:
let someInt : Int? = 42 //方式一:枚舉case模式 if case let .some(x) = someInt { print(x) } if case .some(let x) = someInt { print(x) } //方式二:可選模式 if case let x? = someInt { print(x) }
使用可選模式迭代包含可選項的數(shù)組是很方便的:
enum SomeEnum { case left, right,top,down} let array : Array<SomeEnum?> = [.left,nil,.right,nil,.top,.down] for case let item? in array { print(item)//!< log:left right top down } for case let .some(item) in array { print(item)//!< log:left right top down } for case .some(let item) in array { print(item)//!< log:left right top down }
表達式模式
表達式模式:表示表達式的值,僅出現(xiàn)在 switch 語句的 case 標簽中。
表達式模式的機制:使用Swift標準庫中的 ~= 操作符將表達式模式中表達式的值與匹配值(輸入值)進行比較,若 ~= 返回 true 則證明匹配成功,否則匹配失敗。
~= 運算符默認情況下使用 == 運算符比較兩個相同類型的值;也可以通過檢查某個值是否在某個范圍內(nèi)來匹配范圍值。
let point = (9,14) switch point { case (9,14): print("表達式模式使用`~=`精準匹配::(\(point.0),\(point.1))") fallthrough case (5..<10,0...20): print("表達式模式使用`~=`范圍匹配:(\(point.0),\(point.1))") default: print("未匹配") }
可以重載 〜= 運算符提供自定義表達式匹配行為:
//全局聲明:class外部,否則報錯 func ~= (pattern: String, value: Int) -> Bool { return pattern == "\(value)" } let point = (9,14) switch point { case ("9","14")://若不重載則會報錯 print("表達式模式使用`~=`精準匹配:(\(point.0),\(point.1))") fallthrough case (5..<10,0...20): print("表達式模式使用`~=`范圍匹配:(\(point.0),\(point.1))") default: print("未匹配") }
介紹完模式,接下來我們舉例來說明模式在 Any 和 AnyObject 的類型轉(zhuǎn)換的使用。 示例一:
var things : [Any] = [0, 0.0, 42, 3.14159, "hello", (3.0, 5.0), WhiteCat(),{ (name: String) -> String in "Hello, \(name)" } ] for thing in things { switch thing { case 0 as Int: print("`as`模式匹配兩部分,pattern:表達式模式(`0`),type:匹配類型(`Int`),匹配結(jié)果:0") case (0) as Double: print("`as`模式匹配兩部分,pattern:表達式模式(`0`),type:匹配類型(`Double`),匹配結(jié)果:0.0") case is Double: print("`is`模式匹配`Double`類型的值,值類型與`is`右側(cè)類型及子類相同時,執(zhí)行此句") case let someInt as Int: print("`as`模式匹配兩部分,pattern:值綁定模式(`let someInt`),type:匹配類型(`Int`),匹配結(jié)果:\(someInt)") case _ as Int: print("`as`模式匹配兩部分,pattern:通配符模式(`_`),type:匹配類型(`Int`),匹配結(jié)果被忽略") case let someDouble as Double where someDouble > 0: print("`as`模式匹配兩部分,pattern:值綁定模式(`let someDouble`),type:匹配類型(`Double`),匹配結(jié)果:\(someDouble)") case let someString as String: print("`as`模式匹配兩部分,pattern:值綁定模式(`let someString`),type:匹配類型(`String`),匹配結(jié)果:\(someString)") case let (x, y) as (Double, Double): print("`as`模式匹配兩部分,pattern:元組模式(`let (x, y) `),type:匹配類型(元組`(Double, Double)`),匹配結(jié)果:\((x, y))") fallthrough case (2.0...4.0, 3.0...6.0) as (Double, Double): print("`as`模式匹配兩部分,pattern:表達式模式(`(2.0...4.0, 3.0...6.0) `),type:匹配類型(元組`(Double, Double)`))") case let cat as WhiteCat: print("`as`模式匹配兩部分,pattern:值綁定模式(`let cat`),type:匹配類型(對象`WhiteCat`),匹配結(jié)果:\(cat)") case let sayHelloFunc as (String) -> String: print("`as`模式匹配兩部分,pattern:值綁定模式(`let sayHelloFunc`),type:匹配類型(函數(shù)`(String) -> String`),匹配結(jié)果:\(sayHelloFunc("QiShare"))") default: print("其他結(jié)果,未匹配到") } }
示例二:
let point = (9,14) switch point { case (9,14): print("表達式模式使用`~=`精準匹配::(\(point.0),\(point.1))") fallthrough case (5..<10,0...20): print("表達式模式使用`~=`范圍匹配:(\(point.0),\(point.1))") default: print("未匹配") }
參考資料: swift 5.1官方編程指南
總結(jié)
到此這篇關(guān)于Swift 5.1 之類型轉(zhuǎn)換與模式匹配的教程詳解的文章就介紹到這了,更多相關(guān)Swift 類型轉(zhuǎn)換與模式匹配內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Swift并發(fā)系統(tǒng)并行運行多個任務(wù)使用詳解
這篇文章主要為大家介紹了Swift并發(fā)系統(tǒng)并行運行多個任務(wù)使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06深入探究Swift枚舉關(guān)聯(lián)值的內(nèi)存
這篇文章主要給大家介紹了關(guān)于Swift枚舉關(guān)聯(lián)值的內(nèi)存的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者使用Swift具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08