Swift 5.1 之类型转换与模式匹配的教程详解
类型转换在Swift中使用is和as操作符实现。
类型检查
使用操作符is检查一个实例是否是某个确定的类以及其继承体系的父类或子类类型。如果是某个确定的类(该类继承体系的父类或子类)类型,则返回true,否则返回false。
classCat{
funchairColor()->String{
return"五颜六色"
}
}
classWhiteCat:Cat{
overridefunchairColor()->String{
return"白色"
}
}
classBlackCat:Cat{
overridefunchairColor()->String{
return"黑色"
}
}
//必须符合`Cat`类以及其子类,类型推断需要
letkinds=[WhiteCat(),BlackCat(),WhiteCat(),WhiteCat()]
foriteminkinds{
ifitemisWhiteCat{
print("白猫")//!<3次
}
ifitemisBlackCat{
print("黑猫")//!<1次
}
ifitemisCat{
print("猫")//!<4次
}
}
向下转换
某个类类型的常量或变量实际上可能是其子类的实例。这种情况下,我们会用到类型转换操作符(as?或as!)向下转换为子类类型。
as?:类型转换的条件形式,向下转换为某个类型时,返回该类型的可选值,即:转换失败时返回nil。使用场景:向下转换可能会失败的情况。
as!:类型转换的强制形式,向下转换为某个类型时,会进行强制解包,即:转换失败时触发运行时错误。使用场景:向下转换确定不会失败
//必须符合`Cat`类以及其子类,类型推断需要
letkinds=[WhiteCat(),BlackCat(),WhiteCat(),WhiteCat()]
foriteminkinds{
ifletwhite=itemas?WhiteCat{
print("毛发:\(white.hairColor())")
}
ifletblack=itemas?BlackCat{
print("毛发:\(black.hairColor())")
}
}
下述内容总结自苹果官方博客:
Swift1.2之前as运算符可以执行两种不同类型的转换:保证转换和强制转换。
保证转换:保证将一种类型的值转换为另一种类型,这种保证由编译器编译时验证。
例如:
•向上转换(Upcasting),将当前类型的值转换为该类型的父类之一。
•指定数字的类型:letnum=6asFloat
**强制转换:**强制将一种类型的值转换为另一种类型,这种转换编译器无法保证安全性,并且可能触发运行时错误。
例如:上述的向下转换(Downcasting),将一种类型的值转换为其子类之一。在Swift1.2之后保证转换仍然使用as操作符,但强制转换使用as!操作符。
Any和AnyObject的类型转换
Swift提供了两种特殊类型来处理非特定类型:
any
AnyObject
在某些使用any和AnyObject的特殊场景下,对于Any和AnyObject表示的实例,需要运用类型转换模式,值绑定模式,表达式模式等模式匹配的知识。所以我们先介绍下Swift中的模式。
类型转换模式
类型转换有两种模式:is模式和as模式。is模式仅在switch语句的case标签中使用。is模式和as模式有如下形式:
is<#Type#> //pattern:代表此处也需要一个模式 <#pattern#>as<#Type#>
is模式:如果运行时值的类型与is模式右侧指定的类型或该类型的子类相同,则is模式会匹配到这个值。此行为很适用switch语句的case场景。is模式的行为类似于is运算符,因为它们都执行类型转换但类型转换后丢弃了返回的类型。
as模式:如果在运行时值的类型与as模式右侧指定的类型或该类型的子类相同,则as模式会匹配到这个值。如果匹配成功,则会将匹配到的值的类型将转换为as模式右侧指定的类型。
值绑定模式
值绑定模式将匹配到的值绑定到变量或常量。将匹配到的值绑定到常量,绑定模式以let关键字开头;绑定到变量以var关键字开头。
letpoint=(3,2)
switchpoint{
caselet(x,y):
//值绑定模式匹配到的X值:3,Y值:2
print("值绑定模式匹配到的X值:\(x),Y值:\(y)")
}
通配符模式
通配符模式匹配并忽略任何值,并由下划线_表示。
for_in1...9{
print("通配符模式")
}
标识符模式
标识符模式匹配任何值,并将匹配的值绑定到变量或常量的名称。
letsomeValue=42
someValue是一个与Int类型的值42匹配的标识符模式。匹配成功,42将被赋值给常量someValue。当变量或常量声明的左侧的模式是标识符模式时,标识符模式隐式地是值绑定模式的子模式。####元组模式元组模式是以逗号分隔的零个或多个元素列表,括在括号中。元组模式匹配相应元组类型的值。
包含单个元素的元组模式周围的括号无效。该模式匹配该单个元素类型的值。所以下面写法是等效的:
leta=2//a:Int=2 let(a)=2//a:Int=2 let(a):Int=2//a:Int=2
枚举Case模式
枚举Case模式匹配现有枚举中存在case。枚举Case模式出现在switch语句的case标签中以及if,while, guard,for-in语句中。
如果尝试匹配的枚举case具有关联值,则相应的枚举Case模式必须指定与每个关联值对应的元组。
enumVendingMachineError{
caseInvalidGoods//!<商品无效
caseStockInsufficient//!<库存不足
caseCoinInsufficient(coinNeeded:Int,caseDes:String)
}
letenumArray=[VendingMachineType.CoinInsufficient(coinNeeded:4,caseDes:"自动售货机,硬币不足,请补充"),
.InvalidGoods,
.StockInsufficient,
.CoinInsufficient(coinNeeded:6,caseDes:"自动售货机,硬币不足,超过限额")]
forpatternCaseinenumArray{
switchpatternCase{
case.CoinInsufficient(coinNeeded:letx,caseDes:lety)wherex>5:
print(x,y)
caselet.CoinInsufficient(coinNeeded:x,caseDes:y):
print(x,y)
case.InvalidGoods:
print("商品无效")
default:
print("未匹配到")
}
}
枚举Case模式还匹配枚举类型的可选项。当可选项Optional是枚举类型时,.none和.some能够作为枚举类型的其他case出现在同一个switch语句中。这种简化的语法允许我们省略可选模式。
enumSomeEnum{caseleft,right,top,down}
letarray:Array=[.left,nil,.right,.top,.down]
//方式一:
array.forEach{(item)in
switchitem{
case.left?:
print("左")
caseSomeEnum.right?:
print("右")
case.down?:
print("下")
case.top?:
print("上")
default:
print("没有值")
}
}
//方式二:
array.forEach{(item)in
switchitem{
case.some(letx):
print("对可选项item进行解包得到:\(x)")//!
可选模式
可选模式匹配包含在Optional枚举(这是可选项的实现原理)对应的case项:some(Wrapped)中的值。即匹配可选项有值的情况。
publicenumOptional:ExpressibleByNilLiteral{
///Theabsenceofavalue.
///Incode,theabsenceofavalueistypicallywrittenusingthe`nil`
///literalratherthantheexplicit`.none`enumerationcase.
casenone
///Thepresenceofavalue,storedas`Wrapped`.
casesome(Wrapped)
......
}
可选模式由标识符模式组成后面紧跟?并出现在与枚举Case模式相同的位置。因为可选模式是Optional枚举的Case模式语法糖。所以下面两种写法是等效的:
letsomeInt:Int?=42
//方式一:枚举case模式
ifcaselet.some(x)=someInt{
print(x)
}
ifcase.some(letx)=someInt{
print(x)
}
//方式二:可选模式
ifcaseletx?=someInt{
print(x)
}
使用可选模式迭代包含可选项的数组是很方便的:
enumSomeEnum{caseleft,right,top,down}
letarray:Array=[.left,nil,.right,nil,.top,.down]
forcaseletitem?inarray{
print(item)//!
表达式模式
表达式模式:表示表达式的值,仅出现在switch语句的case标签中。
表达式模式的机制:使用Swift标准库中的~=操作符将表达式模式中表达式的值与匹配值(输入值)进行比较,若~=返回true则证明匹配成功,否则匹配失败。
~=运算符默认情况下使用==运算符比较两个相同类型的值;也可以通过检查某个值是否在某个范围内来匹配范围值。
letpoint=(9,14)
switchpoint{
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{
returnpattern=="\(value)"
}
letpoint=(9,14)
switchpoint{
case("9","14")://若不重载则会报错
print("表达式模式使用`~=`精准匹配:(\(point.0),\(point.1))")
fallthrough
case(5..<10,0...20):
print("表达式模式使用`~=`范围匹配:(\(point.0),\(point.1))")
default:
print("未匹配")
}
介绍完模式,接下来我们举例来说明模式在Any和AnyObject的类型转换的使用。示例一:
varthings:[Any]=[0,0.0,42,3.14159,"hello",(3.0,5.0),
WhiteCat(),{(name:String)->Stringin"Hello,\(name)"}]
forthinginthings{
switchthing{
case0asInt:
print("`as`模式匹配两部分,pattern:表达式模式(`0`),type:匹配类型(`Int`),匹配结果:0")
case(0)asDouble:
print("`as`模式匹配两部分,pattern:表达式模式(`0`),type:匹配类型(`Double`),匹配结果:0.0")
caseisDouble:
print("`is`模式匹配`Double`类型的值,值类型与`is`右侧类型及子类相同时,执行此句")
caseletsomeIntasInt:
print("`as`模式匹配两部分,pattern:值绑定模式(`letsomeInt`),type:匹配类型(`Int`),匹配结果:\(someInt)")
case_asInt:
print("`as`模式匹配两部分,pattern:通配符模式(`_`),type:匹配类型(`Int`),匹配结果被忽略")
caseletsomeDoubleasDoublewheresomeDouble>0:
print("`as`模式匹配两部分,pattern:值绑定模式(`letsomeDouble`),type:匹配类型(`Double`),匹配结果:\(someDouble)")
caseletsomeStringasString:
print("`as`模式匹配两部分,pattern:值绑定模式(`letsomeString`),type:匹配类型(`String`),匹配结果:\(someString)")
caselet(x,y)as(Double,Double):
print("`as`模式匹配两部分,pattern:元组模式(`let(x,y)`),type:匹配类型(元组`(Double,Double)`),匹配结果:\((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)`))")
caseletcatasWhiteCat:
print("`as`模式匹配两部分,pattern:值绑定模式(`letcat`),type:匹配类型(对象`WhiteCat`),匹配结果:\(cat)")
caseletsayHelloFuncas(String)->String:
print("`as`模式匹配两部分,pattern:值绑定模式(`letsayHelloFunc`),type:匹配类型(函数`(String)->String`),匹配结果:\(sayHelloFunc("QiShare"))")
default:
print("其他结果,未匹配到")
}
}
示例二:
letpoint=(9,14)
switchpoint{
case(9,14):
print("表达式模式使用`~=`精准匹配::(\(point.0),\(point.1))")
fallthrough
case(5..<10,0...20):
print("表达式模式使用`~=`范围匹配:(\(point.0),\(point.1))")
default:
print("未匹配")
}
参考资料:swift5.1官方编程指南
总结
到此这篇关于Swift5.1之类型转换与模式匹配的教程详解的文章就介绍到这了,更多相关Swift类型转换与模式匹配内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!