swift 可选值

来源:互联网 发布:javascript 调用堆栈 编辑:程序博客网 时间:2024/06/06 04:05

// 可选值

let cities_ = ["Paris": 2241, "Madrid": 3165, "Amsterdam": 827, "Berlin": 3562]

//  madridPopulation 的类型是可选类型 Int?,而非 Int。一个 Int? 类型的值是 Int 或者特

//殊的缺失 nil

let madridPopulation: Int? = cities_["Madrid"]

// 检验查询是否成功

// madridPopulation! 是为了 获取可选值中实际的 Int 值。后缀运算符 ! 强制将一个可选类型转换为一个不可选类型

if (madridPopulation != nil) {

    print("The population of Madrid is \(madridPopulation! * 1000)")

} else {

    print("Unknown city: Madrid")

}

if let madridPopulation = cities_["Madrid"] {

    print("The population of Madrid is \(madridPopulation * 1000)")

} else {

    print("Unknown city: Madrid")

}

/**

如果 optional 变量是非 nil 的话,我们真的不愿意对 defaultValue 进行求值 —— 

因为这可能是一个开销非常大的计算,只有绝对必要时我们才会想运行这段代码

*/

 

 /**

 Swift 还给 ! 运算符提供了一个更安全的替代,?? 运算符。使用这个运算符时,需要额外提供 一个默认值,当运算符被运用于 nil ,这个默认值将被作为返回值

 

 ?? 运算符会检验它的可选参数是否为 nil。如果是,返回 defaultValue 参数;否则,返回可选 值中实际的值

 */

//infix operator ??

func ??<T>(optional: T?, defaultValue: T) -> T {

    if let x = optional {

        return x

    } else {

        

        return defaultValue

    }

}

/**

 上面的定义有一个问题:如果 default 的值是通过某个函数或者表达式得到的,那么无论可选 值是否为 nil,defaultValue 都会被求值。

 通常我们并不希望这种情况发生:一个 if-then-else 语句应该根据各分支关联的值是否为真,只执行其中一个分支。同样的道理,?? 运算符应该只 在可选值参数是 nil 时才对 defaultValue 参数进行求值。举个例子,假设我们像下面这样调用 ??:

 

 

 作为 T 类型的替代,我们提供一个 () -> T 类型的默认值。现在 defaultValue 闭包中的代码仅 当我们对它进行调用时才会执行。在这样的定义下,代码会如预期一样,只在 else 分支中被执 行。美中不足的是,当调用 ?? 运算符时需要为默认值创建一个显式闭包。例如,我们需要编写 以下代码:

 myOptional ?? { myDefaultValue }

 */

func ??<T>(optional: T?, defaultValue: () -> T) -> T {

    if let x = optional {

        return x

    }

    else {

        return defaultValue()

    }

}

//Swift autoclosure 类型标签来避开创建显式闭包的需求。

//它会在所需要的闭包中隐式地将参数封装到 ?? 运算符。这样一来,我们能够提供与最初相同的 接口,但是用戶无需再显式地创建闭包封装 defaultValue 参数。Swift 标准库中使用的实际定 义如下:

//?? 运算符提供了一个相较于强制可选解包更安全的替代,并且不像可选绑定一样繁琐

infix  operator ?? { associativity right precedence 110 }

func ??<T>(optional: T?, @autoclosure defaultValue: () -> T) -> T {

    if let x = optional {

        return x

    } else {

        return defaultValue()

        

    }

}

// 玩转可选值

// 可选值链

// 可选链,它用于在被嵌套的类或结构体中对方法或属性进行选择

struct Order {

    let orderNumber: Int

    let person: Person?

}

struct Person {

    let name: String

    let address: Address?

}

struct Address {

    let streetName: String

    let city: String

    let state: String?

}

// 给定一个 Order,如何才能查找到客戶的状态呢?我们可以使用显式解包运算符:

// order.person!.address!.state! 如果任意中间数据缺失,这么做可能会导致运行时异常。使用可选绑定相对更安全

/**

if let myPerson = order.person {

if let myAddress = myPerson.address {

if let myState = myAddress.state { // ...

但这未免有些烦琐。若使用可选链,这个例子将会变成:

*/

var address = Address(streetName: "guangzhou",city: "huangpu",state: "wengcong")

var person = Person(name: "RHC",address:address)

var order = Order(orderNumber: 8,person:person)

// 使用问号运算符来尝试对可选类型进行解包,而不是强制将它们解包。当任意一个组成项 失败时,整条语句链将返回 nil

if let myState = order.person?.address?.state {

    print("This order will be shipped to \(myState)")

} else {

    print("Unknown person, address, or state.")

}

// 分支上的可选值

//if let可选绑定机制,但是Swift还有其他两种分支语句,switch guard,它们也非常适合与可选值搭配使用

/**

我们简单地为 case 分支中的每个模式添加一个 ? 缀。如果我们对一个特定值没有兴趣,也可以直接匹配 Optional None 值或 Some

*/

switch madridPopulation {

case 0?: print("Nobody in Madrid")

case (1..<1000)?: print("Less than a million in Madrid")

case .Some(let x): print("\(x) people in Madrid")

case .None: print("We don't know about Madrid")

}

/**

 guard 语句的设计旨在当一些条件不满足时,可以尽早退出当前作用域。没有值存在时就提早退出,是一个很常⻅的使用情境。将它和可选绑定组合在一起可以很好地处理 None 的情况。 很显然,guard 语句后面的任何代码都需要值存在才会被执行。举个例子,我们可以重写打印 给定城市居⺠数量的代码

 */

func populationDescriptionForCity(city: String) -> String? { guard let population = cities_[city] else { return nil }

    return "The population of Madrid is \(population * 1000)"

}

populationDescriptionForCity("Madrid")

// 可选映射

/**

? 运算符允许我们选择性地访问可选值的方法或字段。然而,在很多其它例子中,若可选值存 ,你可能会想操作它,否则返回 nil

*/

func incrementOptional(optional: Int?) -> Int? {

    guard let x = optional else { return nil }

    return x + 1

}

// MARK: - incrementOptional 函数和 ? 运算符一般化,然后为可选值定义一个 map 函数。这 样一来,我们不仅能像 incrementOptional 那样,对一个 Int? 类型的值做增量运算,还可以将 想要执行的任何运算作为参数传递给 map 函数

// map 函数接受一个类型为 Wrapped -> U transform 函数作为参数。如果可选值不是 nil, map 将会将其作为参数来调用 transform,并返回结果;否则 map 函数将返回 nil。这个 map 函数是 Swift 标准库的一部分

extension Optional {

    func map<U>(transform: Wrapped -> U) -> U? {

        guard let x = self else { return nil }

        return transform(x)

    }

}

// 使用 map 来重写 incrementOptional

func incrementOptional2(optional: Int?) -> Int? {

    return optional.map { $0 + 1 }

}

// 再谈可选绑定

//map 函数展示了一种操作可选值的方法,但是还有很多其它方法存在:

let x: Int? = 3

let y: Int? = nil

// 问题是加法运算只支持 Int ,而不支持我们这里的 Int?

//let z: Int? = x + y 解决:

func addOptionals(optionalX: Int?, optionalY: Int?) -> Int? { if let x = optionalX {

        if let y = optionalY {

            return x + y

        }

    }

    return nil

}

//了层层嵌套,我们还可以同时绑定多个可选:

func addOptionals_(optionalX: Int?, optionalY: Int?) -> Int? { if let x = optionalX, y = optionalY {

      return x + y

    }

    return nil

}

// 想更简短,可以使用一个 guard 语句,当值缺失时提前退出:

func addOptionals__(optionalX: Int?, optionalY: Int?) -> Int?{

    guard let x = optionalX, y = optionalY else {

        return nil

    }

    return x + y

}

let capitals = [

    "France": "Paris",

    "Spain": "Madrid",

    "The Netherlands": "Amsterdam", "Belgium": "Brussels"

]

// 为了编写一个能返回给定国家首都人口数量的函数,我们将 capitals 字典与之前定义的的cities 字典结合。对于每一次字典查询,我们必须确保它返回一个结果

func populationOfCapital(country: String) -> Int? {

    

    guard let capital = capitals[country], population =  cities_[capital]

        else { return nil }

    

    return population * 1000

}

/**

可选链和if let(guardlet)都是语言中让可选值能够更易于使用的特殊构造。不过,Swift 还提供了另一条途径来解决上述问题:那就是借力于标准库中的  flatMap 函数。多种类型中都 定义了 flatMap 函数,在可选值类型的情况下,它的定义是这样的

 flatMap 函数检查一个可选值是否为 nil。若不是,我们将其传递给参数函数 f;若是 nil,那么

 结果也将是 nil

 */

extension Optional {

    func  flatMap<U>(f: Wrapped -> U?) -> U? {

        guard let x = self else { return nil }

        return f(x) }

}

// 使用此函数,重写例子

func addOptionals2(optionalX: Int?, optionalY: Int?) -> Int? {

    return optionalX.flatMap {

        x in optionalY.flatMap { y in return x + y}

    }

}

func populationOfCapital2(country: String) -> Int? {

    return capitals[country].flatMap {

        capital in cities_ [ capital ].flatMap {

            population in return population * 1000

        }

    }

}

// 当前我们通过嵌套的方式调用flatMap,取而代之,也可以通过链式调用来重写

//populationOfCapital2,这样使代码结构更浅显易懂:

func populationOfCapital3(country: String) -> Int? {

    return capitals[country].flatMap {

        capital in return cities_[capital]

        }.flatMap {

            population in return population * 1000

    }

}

0 0
原创粉丝点击