美文网首页
函数式Swift4 - 可选值在函数式编程中

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

作者: 你weixiao的时候很美 | 来源:发表于2018-04-17 15:08 被阅读32次

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

    相关文章

      网友评论

          本文标题:函数式Swift4 - 可选值在函数式编程中

          本文链接:https://www.haomeiwen.com/subject/atwukftx.html