Swift中强大的模式匹配
2018-05-17 本文已影响74人
小凉介
Swift中的模式匹配语法是一个亮点,Swift里switch比OC里面强大很多,switch的主要特性就是模式匹配,所以本文会主要结合switch来讲强大好用的模式匹配。
swift中模式有以下几种:
- 通配符模式(Wildcard Pattern)
- 标识符模式(Identifier Pattern)
- 值绑定模式(Value-Binding Pattern)
- 元组模式(Tuple Pattern)
- 枚举用例模式(Enumeration Case Pattern)
- 可选模式(Optional Pattern)
- 类型转换模式(Type-Casting Pattern)
- 表达式模式(Expression Pattern)
通配符模式
如果在Swift中使用了_
通配符,就表示你是使用了通配符模式,_
用于匹配并忽略任何值。这又分为两种情况:
-
_
:完全不关心这个值,甚至可以为nil
enum Moblie {
case Man(name: String, age: Int, height: Int?)
case Woman(name: String, age: Int, height: Int?)
}
let Roy = Moblie.Man(name: "Roy", age: 27, height: 178)
switch Roy {
case .Man(name: let name, age: let age, height: let height):
print("\(name) -- \(age) -- \(String(describing: height))")
default:
break
}
-
_?
:虽然这个值不使用,但是要确保是非nil的
switch Roy {
case .Man(name: let name, age: _, height: _?):
print("\(name)")
default:
break
}
标识符模式
匹配一个具体的值或者定义变量或者常量时候,可以认为变量名和常量名就是一个标识符模式,用于接收和匹配一个特定类型的值。这种比较简单。
let i = 21 // i 就是一个标识符模式
值绑定模式
值绑定在if
语句和switch
语句中用的较多
switch Roy {
case .Man(name: let name, age: let age, height: let height):
print("\(name) -- \(age) -- \(String(describing: height))")
default:
break
}
也可以这样写
switch Roy {
case let .Man(name: name, age: age, height: height):
print("\(name) -- \(age) -- \(String(describing: height))")
default:
break
}
元组模式
let error = (statusCode: 404, statusMessage: "Not Found")
switch error {
case (let code, _):
print("\(code)")
default:
break
}
这个是在详解 Swift 模式匹配中看到的示例,很赞
let age = 23
let job: String? = "Operator"
let payload: AnyObject = NSDictionary()
switch (age, job, payload) {
case (let age, _?, _ as NSDictionary):
print(age)
default: ()
}
枚举用例模式
enum Result {
case error(String)
case image(UIImage)
case data(Data)
}
let result = Result.error("没有找到资源")
switch result {
case let .image(image):
print(image)
case let .data(data):
print(data)
case .error(let err):
print("Failed; error message is \(err)")
}
可选模式
可选模式就是包含可选变量定义模式,在 if case
、 for case
、 switch-case
会用到。注意 if case let
和 if let
的区别
// 使用可选模式匹配
if case let x? = someOptional {
print(x)
}
let arrayOfOptionalInts: [Int?] = [nil, 2, 3, nil, 5]
// 只匹配非 nil 的元素
for case let number? in arrayOfOptinalInts {
print("Found a \(number)")
}
// Found a 2
// Found a 3
// Found a 5
let count: Int? = 5
switch count {
case 1?:
print("1")
case 3?:
print("3")
case 5?:
print("5")
case _:
print("nil")
default:
break
}
类型转换模式
-
is
类型:匹配右手边内容的运行时类型(或者类型的子类)。它会做类型转换但是不关注返回值。所以你的case块不知道所匹配的类型是什么。 -
as
类型:和is
模式做同样的匹配操作,但是如果成功的话会把类型转换到左侧指定的模式中。
let a: Any = 5
switch a {
// 这会失败因为它的类型仍然是 `Any`
// 错误: binary operator '+' cannot be applied to operands of type 'Any' and 'Int'
case is Int: print (a + 1)
// 有效并返回 '6'
case let n as String: print ("result: "+n)
default: ()
}
表达式模式
可以把 switch 的值和实现了 ~= 操作符的表达式进行匹配
- 范围匹配
let point = (1, 2)
switch point {
case (0, 0):
print("(0, 0) is at the origin.")
case (-2...2, -2...2):
print("(\(point.0), \(point.1)) is near the origin.")
default:
print("The point is at (\(point.0), \(point.1)).")
}
- 自定义
~=
运算符
struct Score {
let Math: Int
let Chinese: Int
let English: Int
}
func ~= (pattern: Int, value: Score) -> Bool {
return value.Math > pattern && value.Chinese > pattern && value.English > pattern
}
let score = Score(Math: 80, Chinese: 40, English: 70)
switch score {
case 90:
print("优秀")
default:
break
}
其他用法
在条件中使用where语句
let people = (age: 27, name: "karl")
switch people {
case (let age, _) where age > 30:
print(age)
default:
break
}
if case let
当只有一个条件的时候,用switch会显得冗余,直接用if case let会使代码读起来更便捷。
let Roy = Moblie.Man(name: "Roy", age: 27, height: 178)
if case let .Man(name, _, _?) = Roy {
print(name)
}
for case let
let array: [Any?] = [1,2,nil,4,54,65,76, ""]
输出这个数组里面大于10的数字
常规写法
for item in array {
if let element = item as? Int, element > 10 {
}
}
for case
写法
for case let x? as Int? in array where x > 10 {
print(x)
}
用Moblie作为例子
let Roy = Moblie.Man(name: "Roy", age: 27, height: 178)
let Kelly = Moblie.Woman(name: "Kelly", age: 28, height: nil)
let Frank = Moblie.Man(name: "Frank", age: 29, height: nil)
let Arvin = Moblie.Man(name: "Arvin", age: 28, height: nil)
let moblieArray = [Roy, Kelly, Frank, Arvin]
for case let .Man(name, age, _?) in moblieArray where age < 29 {
print(name)
}
参考文章: