总结// 可选值
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
}
}
以上是内存溢出为你收集整理的swift 可选值全部内容,希望文章能够帮你解决swift 可选值所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)