// 可选值 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 } }
时间: 2024-10-12 13:08:07