加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

swift 可选值

发布时间:2020-12-14 07:01:00 所属栏目:百科 来源:网络整理
导读:// 可选值 let cities_ = [ "Paris" : 2241 , "Madrid" : 3165 , "Amsterdam" : 827 , "Berlin" : 3562 ] // madridPopulation 的类型是可选类型 Int?, 而非 Int 。一个 Int? 类型的值是 Int 或者特 // 殊的 “ 缺失 ” 值 nil let madridPopulation: Int ?

// 可选值

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",27)"> "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

}

}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读