可选值
Optional是Swift中的一种枚举类型,用来表达某个类型的可能值。
1 2 3 4 enum Optional<Wrapped> { case none case some(Wrapped) }
表示方式
可选值遵守了ExpressibleByNilLiteral
协议,因此可以用nil
来替代.none
而非可选值可以直接表示成可选值
return idx
等价于 return .some(idx)
可选值类型的表示可以在类型的后面加上?
进行表示,如Int?
表示Optional<Int>
类型
解包
要使用可选值中实际的值的话需要进行解包
操作
因为可选值是枚举类型,所以可以使用switch
语法来取出可选值中的值
1 2 3 4 5 6 7 let array = [1, 2, 3] switch array.first { case .some(let first): print(first) // 输出 1 case .none: break }
1 2 3 4 5 6 switch array.first { case let first?: print(first) // 输出 1 case nil: break }
可选绑定
使用switch
的方式太过繁琐
使用if let
语法来进行可选绑定optional binding
,进行解包操作,并且可以和布尔语句进行搭配
1 2 3 if let first = array .first , first > 0 { print (first ) }
可以在if
语句中绑定多个值,并且后面的绑定值可以依据前面成功的解包值来进行操作
1 2 3 4 5 6 7 8 let viewControllers: [String: UIViewController] = ["Home" : HomeViewController]if let vc = viewControllers["Home" ], let homeVC = vc as ? HomeViewController { } ``` * `while let `语句和`if let `类似,`while`语句在当前可选值为`nil`的时候停止循环
let array: [Int?] = [1, 2, 3, nil] let iterator = array.makeIterator() // 迭代器返回最后一个元素后会返回nil while let value = iterator.next() { print(value) // 1 2 3 }1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #### 双重可选值 * 一个可选值本身可以被当作值被另一个可选值包装,导致可选值嵌套在可选值中 * `Optional<Optional<Int>>` = `Int??` ```swift4.0 let array: [Int??] = [1 , 2 , 3 , nil]for a in array { print(a) } 输出: Optional(Optional(1 )) Optional(Optional(2 )) Optional(Optional(3 )) nil
可以使用case
做模式匹配,”脱去”最外层的可选值,nil
元素也被过滤掉了
case let a?
是case .some(let a)
的一种写法
1 2 3 4 5 6 7 8 let array: [Int??] = [1, 2, 3, nil] for case let a? in array { print(a) } 输出: Optional(1) Optional(2) Optional(3)
可选链
Swift
中没办法向一个nil
对象发送消息,但可选链可以实现一样的效果
1 2 let str: String? = "abc" let upperStr = str?.uppercased() // Optional<"ABC">
1 2 var str: String? let upperStr = str?.uppercased() // nil
可选链的执行结果都是可选值,str
不为nil
的时候,可以得到执行uppercased
饭后之后的值。若str
为nil
则?
后面的方法都不会被调用。因为得到的结果需要考虑str
是否为nil
的情况,所以将值设置为可选值。
可选链是一个展平操作
1 2 3 let str: String? = "abc" let upperStr = str?.uppercased().lowercased() // 结果是 Optional("ABC") 而不是 Optional(Optional("abc"))
1 2 3 4 5 6 var closure: ((Int) -> ())? closure?(1) // closure 为 nil 不执行 let dict = ["one": 1, "two": 2] dict?["one"] // Optional(1) dict?["three"] // nil
通过可选链进行赋值,先判断当前变量是否为nil
,不为nil
的进行赋值
1 2 3 4 5 6 7 var a: Int? = 0 a? = 1 a // Optional(1) var b: Int? b? = 1 b // nil
与可选值有关的高阶函数 1. map
这个方法接受一个闭包,如果可选值有内容则调用这个闭包进行转换
1 2 3 var dict = ["one": "1", "two": "2"] let result = dict["one"].map{ Int($0) } // Optional(Optional(1))
上面的代码中我们从字典中取出字符串”1”,并将其转换为Int
类型,但因为String
转换成Int
不一定能成功,所以返回的是Int?
类型,而且字典通过键不一定能取得到值,所以map
返回的也是一个Optional
,所以最后上述代码result
的类型为Int??
类型。
要解决这种问题,需要一个展平
操作
2. flatMap
1 2 3 var dict = ["one": "1", "two": "2"] let result = dict["one"].flatMap{ Int($0) } // Optional(1)
注意,这个方法是作用在Optioanl
的方法,而不是作用在Sequence
上的
作用在Sequence
上的flatMap
方法在Swift4.1
中被更名为compactMap
,该方法可以将序列中的nil
过滤出去
1 2 3 4 5 let array = ["1", "2", "3", nil] let result = array.compactMap{ $0 } // ["1", "2", "3"] let array = ["1", "2", "3", "four"] let result = array.compactMap{ Int($0) } // [1, 2, 3]
可选值与Equatable
可选值有==
操作符,可以用来进行可选值与非可选值之间的比较,前提是可选值中的类型是可比较的
1 2 3 4 5 6 7 func ==<T: Equatable>(lhs: T?, rhs: T?) -> Bool { switch (lhs, rhs) { case (nil , nil ): return true case let (x?, y?): return x == y case (_ ?, nil ), (nil , _ ?): return false } }
但是,这样并不是说明可选值类型遵守了Equatable
协议,可选值在Swift4
之前是没有实现Equatable
的
1 2 3 let a = [1 , 2 , nil ]let b = [1 , 2 , nil ]a == b
Swift 4.1’s Optional, Array and Dictionary now conform to Equatable and Hashable whenever their underlying values or elements conform to these protocols.