Swift十七(1: 字面量 2: 匹配模式)
1 字面量协议
2 匹配模式 (可选类型, where)
一: 字面量
1 字面量
1. var age = 10
2. var isRed = false
3. var name = "jack"
上面代码中的10、false、"Jack"就是字面量 ( 通过字面推断变量类型, 并且能初始化对象 )
正常初始化是 例如Person类 var p = Person(), 而字面量可以直接初始对象
2 常见字面量的默认类型 标准库定义的别名
public typealias IntegerLiteralType = Int
public typealias FloatLiteralType = Double
public typealias BooleanLiteralType = Bool
public typealias StringLiteralType = String
Swift自带的绝大部分类型,都支持直接通过字面量进行初始化
可以通过typealias修改字面量的默认类型
3 字面量协议
Bool : ExpressibleByBooleanLiteral
Int : ExpressibleByIntegerLiteral
Float、Double : ExpressibleByIntegerLiteral、ExpressibleByFloatLiteral
Dictionary : ExpressibleByDictionaryLiteral
String : ExpressibleByStringLiteral
Array、Set : ExpressibleByArrayLiteral
Optional : ExpressibleByNilLiteral
// 例如: ExpressibleByIntegerLiteral协议(Int协议)
public protocol ExpressibleByIntegerLiteral {
associatedtype IntegerLiteralType : _ExpressibleByBuiltinIntegerLiteral
init(integerLiteral value: Self.IntegerLiteralType)
}
Swift自带类型之所以能够通过字面量初始化,是因为它们遵守了对应的协议
遵守协议, 实现init方法, 从而初始化对象
4 字面量协议应用
// 例一: 通过Bool字面量, 初始化Int类型
extension Int : ExpressibleByBooleanLiteral {
public init(booleanLiteral value: Bool) {
self = value ? 1 : 0 }
}
var num: Int = true // bool类型初始化 Int
print(num) // 1
// 例二: 通过通过数组 字典字面量, 初始化结构体Point类型
struct Point {
var x = 0.0, y = 0.0
}
// 分别遵守了, 数组和字典的协议
extension Point : ExpressibleByArrayLiteral, ExpressibleByDictionaryLiteral {
// 数组协议方法
init(arrayLiteral elements: Double...) {
guard elements.count > 0 else { return }
self.x = elements[0]
guard elements.count > 1 else { return }
self.y = elements[1]
}
// 字典协议方法
init(dictionaryLiteral elements: (String, Double)...) {
for (k, v) in elements {
if k == "x" {
self.x = v
} else if k == "y" {
self.y = v
}
}
}
}
var p: Point = [10.5, 20.5] // 数组字面量, 初始化结构体
print(p) // Point(x: 10.5, y: 20.5)
p = ["x" : 11, "y" : 22] // 字典字面量, 初始化结构体
print(p) // Point(x: 11.0, y: 22.0)
// Double...代表可变数组元素Double类型
// (String, Double)..代表可变字典, 键值对: 字符串: double
二: 模式匹配
1 通配符模式(Wildcard Pattern)
_ 匹配任何值
_? 匹配非nil值
// 通配符模式(Wildcard Pattern)
enum Life { // 定义枚举
case human(name: String, age: Int?)
case animal(name: String, age: Int?)
}
func check(_ life: Life) {
switch life {
case .human(let name, _): // 匹配任何值
print("human", name)
case .animal(let name, _?): // 不能为nil
print("animal", name)
default:
print("other") }
}
check(.human(name: "Rose", age: 20)) // human Rose
check(.human(name: "Jack", age: nil)) // human Jack
check(.animal(name: "Dog", age: 5)) // animal Dog
check(.animal(name: "Cat", age: nil)) // other
// 注意最后返回other, age不能为nil, 所以执行default
2 值绑定模式(Value-Binding Pattern)
let point = (3, 2)
switch point {
case let (x, y):
print("The point is at(\(x),\(y)")
// 3,2分别绑定 x, y
3 元祖模式
let points = [(0, 0), (1, 0), (2, 0)]
for (x, _) in points {
print(x)
}
let name: String? = "jack"
let age = 18
let info: Any = [1, 2]
switch (name, age, info) {
case (_?, _ , _ as String):
print("case")
default:
print("default")
}
// 遍历字典
var scores = ["jack" : 98, "rose" : 100, "kate" : 86]
for (name, score) in scores {
print(name, score)
}
4 枚举case模式
let age = 2
// 1 原来的写法
if age >= 0 && age <= 9 {
print("[0, 9]")
}
// 2 枚举Case模式
if case 0...9 = age { // 匹配 age在0到9区间, 同上
print("[0, 9]")
}
// 3 guard
guard case 0...9 = age else { return }
print("[0, 9]")
// 4 switch
switch age {
case 0...9: print("[0, 9]")
default: break
}
// 数组遍历
let ages: [Int?] = [2, 3, nil, 5]
for case nil in ages {
print("有nil值")
break
} // 有nil值
// 数组元祖
let points = [(1, 0), (2, 1), (3, 0)]
for case let (x, 0) in points {
print(x)
} // 13
5 可选模式
let age: Int? = 42
if case .some(let x) = age { // 可选项绑定x
print(x)
}
if case let x? = age { // 可选项绑定x
print(x)
}
let ages: [Int?] = [nil, 2, 3, nil, 5]
for case let age? in ages { // 条件可选项有值, let age 可选绑定解包
print(age)
} // 2 3 5
let ages: [Int?] = [nil, 2, 3, nil, 5]
for item in ages { // 遍历
if let age = item { // 可选绑定 非空打印
print(age)
}
} // 跟上面的for,效果是等价的
func check(_ num: Int?) {
switch num {
case 2?: print("2")
case 4?: print("4")
case 6?: print("6")
case _?: print("other")
case _: print("nil")
}
}
check(4) // 4
check(8) // other
check(nil) // nil
5 类型转换模式
is: 判断类型 case is Int:
as: 类型转换 case let n as String
as? 类型转换, 转换成功为可选类型, 转换失败为nil
as! 类型转换, 功能同as? 转换失败crash
补充:
Any : 表示任意类型
AnyObject: 表示任意类类型
AnyClass: 表示类的原类型 typealias AnyClass = AnyObject.Type
let num: Any = 10
let num: Any = "哈哈"
switch num {
case is Int: // num是否为Int类型
print("is Int", num) // 虽然真实类型是Int, 但是编译器依然认为num是Any类型
case let n as String: // 如果num能强转String, 则把num转成n
print("as string---\(n)")
default:
print("啥也不是")
break
}
// let num: Any = "10" 打印 is Int 10
// let num: Any = "哈哈" 打印 as string---哈哈
6 表达式模式
表达式模式运用在case中
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)).")
} // (1, 2) is near the origin
7 自定义表达式模式
可以通过重载运算符,自定义表达式模式匹配规则
func isEven(_ i: Int) -> Bool { i % 2 == 0 } // 偶数
func isOdd(_ i: Int) -> Bool { i % 2 != 0 } // 基数
extension Int {
// 1: pattern为case后面的内容 2: value为switch后面的值
static func ~= (pattern: (Int) -> Bool, value: Int) -> Bool {
pattern(value) // isEven传给pattern age传给value
}
}
var age = 9
switch age {
case isEven:
print("偶数")
case isOdd:
print("奇数")
default:
print("其他")
}
补充: { // 闭包中...} $0 代表第一个参数
// 需求判断一个字符串, 是否为另一个字符串的前缀
func hasPrefix1(str: String, pre: String) -> Bool {
return str.hasPrefix(pre)
}
// prefix 是否为前缀字符换,
func hasPrefix2(_ prefix: String) ->((String) -> Bool) {
// return { (str: String) -> Bool in
// return str.hasPrefix(prefix)
// }
// { (str: String) -> Bool in
// str.hasPrefix(prefix)
// }
{
$0.hasPrefix(prefix) // 代表第一个参数 str: String
}
}
override func viewDidLoad() {
super.viewDidLoad()
// 需求判断一个字符串, 是否为另一个字符串的前缀
let isPre = hasPrefix1(str: "123456", pre: "123") // true
let fn = hasPrefix2("123")("123456") // true
}
8 where条件
可以使用where为模式匹配增加匹配条件
<1> switch 添加条件语句
var data = (10, "Jack")
switch data {
case let (age, _) where age > 10:
print(data.1, "age > 10")
case let (age, _) where age > 0:
print(data.1, "age > 0")
default: break
}
<2> for循环 添加条件语句
var ages = [10, 20, 44, 23, 55]
for age in ages where age > 30 {
print(age)
} // 44 55
<3> 协议 添加条件语句
protocol Stackable { associatedtype Element }
protocol Container {
associatedtype Stack : Stackable where Stack.Element : Equatable
}
// 1 协议 Continer内部的关联类型Stack需要遵守Stackable协议
// 2 关联类型Stack的关联类型Element需要遵守Equatable协议
<4> func方法 添加条件语句
func equal<S1: Stackable, S2: Stackable>(_ s1: S1, _ s2: S2) -> Bool
where S1.Element == S2.Element, S1.Element : Hashable {
return false
}
<5> 扩展 条件语句
extension Container where Self.Stack.Element : Hashable { }