函数式Swift4 - 可选值在函数式编程中

2018-04-17  本文已影响32人  你weixiao的时候很美

本文是一个系列,是函数式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等处理可选值为空的情况。

上一篇下一篇

猜你喜欢

热点阅读