本文是一个系列,是函数式Swift的读书笔记(其实是为了备忘)
1.案例研究:字典
通过key来从字典中取出的值是可选值,
let cities = ["Paras":2231,
"Madrid":2345,
"Beijing":3000
]
let beijingPopulation: Int? = cities["Beijing"]
Swift有一个可选绑定机制,可以避免使用强制解绑可选值为空时引发的crash
if let madridPopulation = cities["madrid"] {
print("the population of madird is \(madridPopulation*1000)")
}else{
// 没取到
}
Swift还给强制解包一个安全的替代方案 ?? 运算符,使用的时候,需要额外提供一个默认值。当运算返回nil时,这个默认值将被用作返回值。
//实现方式
infix operator ??
func ??<T>(optional:T?,defaultValue:T)->T{
if let x = optional{
return x
}else{
return defaultValue
}
}
//上面的定义有一个问题:如果 defaultValue 的值是通过某个函数或者表达式计算得到的,那么无论可选值是否为 nil,defaultValue 都会被求值。
解决这个问题,可以用如下的方式
infix operator ??
func ??<T>(optional:T?,detaultValue:()->T)->T{
if let x = optional {
return x
}else{
return detaultValue()
}
}
//作为 T 类型的替代,我们提供一个 () -> T 类型的默认值。现在 defaultValue 函数中的代码只在 else 分支中会被执行
我们需要编写一下类型的代码:
myOptional ?? { myDefaultValue }
// Swift的标准库中,??的实现方式就是这样的,但是使用@autoclosure标签来避开显式的创建闭包。
// 其实还有其他处理的方式,使用guard,使用flatMap() 函数。
2. 玩转可选值。
2.1 可选链
Swift 有一个特殊的机制,可选链,它用于在被嵌套的类或结构体中调用方法或访问属性
struct Order{
let orderNumber : Int
let persion : Persion?
}
struct Persion{
let name : String
let address : Address?
}
struct Address{
let streetName:String
let state : String?
}
let order = Order(orderNumber: 42, persion: nil)
if let myState = order.persion?.address?.state{
print("the order will be shipped to \(myState)")
}else{
//没取到
}
2.2 分支上的可选值
上边是使用if let 可选绑定,switch和guard也非常适合可选搭配使用
// switch 语句匹配可选值,简单的为case后的模式添加一个?
switch beijingPopulation {
case let x? :
print("\(x) people in beijng")
case nil:
print("we dont know about beijing")
}
//guard 语句处理可选值非常常见,空值和不符合值提前退出
func populationDescription(for city:String)->String?{
guard let population = cities[city] else {
return nil
}
return "city\(city) has population \(population)"
}
2.3 FlatMap()
let x: Int? = 3
let y: Int? = nil
let z: Int? = x+y
//这段编译出问题,因为+ 号不支持可选值。
//可以用可选绑定嵌套
func add(_ optionalX: Int?, _ optionalY: Int?) -> Int? {
if let x = optionalX {
if let y = optionalY {
return x + y
}
}
return nil
}
//同时多个可选绑定:
func add2(_ optionalX: Int?, _ optionalY: Int?) -> Int? {
if let x = optionalX, let y = optionalY {
return x + y
}
return nil
}
//可以用guard
func add3(_ optionalX: Int?, _ optionalY: Int?) -> Int? {
guard let x = optionalX, let y = optionalY else { return nil }
return x + y
}
//Swift 还提供了另一条途径来解决上述问题:那就是借力于标准库中的 flatMap 函数。多种类型中都定义了flatMap 函数,在可选值类型的情况下,它的定义是这样的:
extension Optional {
func flatMap<U>(_ transform: (Wrapped) -> U?) -> U? {
guard let x = self else { return nil }
return transform(x)
}
}
//flatMap 函数检查一个可选值是否为 nil。若不是,我们将其传递给参数函数 transform;若是,那么结果也将是 nil
func add4(_ optionalX: Int?, _ optionalY: Int?) -> Int? {
return optionalX.flatMap { x in
optionalY.flatMap { y in
return x + y
}
}
}
3. 为何使用可选值
OC中不使用可选择,在某些情况下,nil将会造成crash。 Swift强迫我们必选用let,guard,flatMap等处理可选值为空的情况。
网友评论