可选项(Optional)
一些定义和解包练习
func execOptional() {
// 定义
let a: String? = "A"
print(type(of: a)) // Optional<String>
let b: String? = "B"
print(type(of: b)) // Optional<String>
// 强制转换可能为nil,所哟是optional类型
let m = Int("a")
print(type(of: m)) // Optional<Int>
// 可选类型本身是个枚举,有值或者为空
let c: Int? = Optional.some(17)
let d: Int? = Optional.none
print(c ?? -1) // 17
print(d ?? -1) // -1
// 强制解包!
// 表达式判断解包if let temp = c
// 表达式判断解包guard let temp = d
// ??解包
if let temp = c {
print("c不为空", "c的值是:(temp)") // d为空 d的值是:17
}
guard let temp = d else {
print("d为空,但是d的值拿不到") // d为空 d的值是:17
return
}
var string: String? = "Position"
// string?
print(string?.hasPrefix("P")) // Optional(true)
if let temp = string?.hasPrefix("P") {
print(temp) // true 传入Optional() 自动解包
}
string = nil
print(string ?? -999) // -999
}
Optional类型的map和flatMap
如果是可选类型就可以使用map和flatMap
var num1: Int? = 10
var num2 = num1.map { $0 * 2 } // Optional(20)
var num3: Int? = nil
var num4 = num3.map { $0 * 2 } // nil
// 注意flatMap发现已经是Optional类型了就不会再包装一层了
var numA: Int? = 10
var numB = numA.map { Optional.some($0 * 2) } // Optional(Optional(20))
var numC = numA.flatMap { Optional.some($0 * 2) } // Optional(20)
Optional类型的map和flatMap具体用途
下面几个例子就是我们想对一个Optional进行判断如果有值,就先对Optional解包进行闭包处理,如果为nil就不处理,如果有值的话返回处理后的Optional。闭包处理很灵活,也可以是函数。
$0 是传入解包后的值
var num11: Int? = 10
var num22 = (num1 != nil) ? (num1! + 10) : nil
var num33 = num1.map { $0 + 10 } // num22、num33是等价的
var fmt = DateFormatter()
fmt.dateFormat = "yyyy-MM-dd"
var str: String? = "2011-09-10"
var date1 = str != nil ? fmt.date(from: str!) : nil
var date2 = str.flatMap { fmt.date(from: $0) } // Optional(2011-09-09 16:00:00 +0000)
struct Person {
var name: String
var age: Int
}
var items = [
Person(name: "jack", age: 20),
Person(name: "rose", age: 21),
Person(name: "kate", age: 22)
]
func getPerson2(_ name: String) -> Person? {
return items.firstIndex { $0.name == name }.map { items[$0] }
}
struct Person {
var name: String
var age: Int
init?(_ json: [String: Any]) {
guard let name = json["name"] as? String,
let age = json["age"] as? Int
else {
return nil
}
self.name = name
self.age = age
}
}
// old
var p1 = json != nil ? Person(json!) : nil
// new
var p2 = json.flatMap(Person.init)
可选链(Optional Chaining)
可选链描述的是一个对象是可选类型,它所包含的属性、方法下标也需要解包后处理。以及后续的属性变成可选项。
如下面的代码本身不是可选项的dog,weight,price也变成了可选项
var dog = person?.dog // Dog?
var weight = person?.dog.weight // Int?
var price = person?.car?.price // Int?
多个?可以链接在一起
如果链中任何一个节点是nil,那么整个链就会调用失败
class Car { var price = 0 }
class Dog { var weight = 0 }
class Person {
var name: String = "jack"
var dog: Dog = .init()
var car: Car? = Car()
func age() -> Int { 18 }
func eat() { print("Person eat") }
subscript(index: Int) -> Int { index }
}
var person: Person? = Person()
var age1 = person!.age() // Int
var age2 = person?.age() // Int?
var name = person?.name // String?
var index = person?[6] // Int?
print(person?.name) // Optional("jack")
print(type(of: person?.name)) // Optional<String>
if let temp = person {
print(temp.name) // jack
}
var dog = person?.dog // Dog?
var weight = person?.dog.weight // Int?
var price = person?.car?.price // Int?
如果可选项为nil,调用方法、下标、属性失败,结果为nil
如果可选项不为nil,调用方法、下标、属性成功,结果会被包装成可选项
如果结果本来就是可选项,不会进行再次包装
OC里面可以给空对象发送消息,Swift中空对象是不会调用方法的。
下例中不会调用getName()
func getName() -> String {
"jack" //person为nil的时候不会执行改方法
}
var person: Person? = Person()
person = nil
person?.name = getName()
字典?的应用
var scores = ["Jack": [86, 82, 84],
"Rose": [79, 94, 81]]
scores["Jack"]?[0] = 100
let _:Int? = scores["Jack"]?[0] //Optional(100)
scores["Rose"]?[2] += 10
let _ = scores["Rose"]?[2] //Optional(91)
scores["Kate"]?[0] = 88
下例子num1和num1?的区别
使用num1?的时候先判断num1是不是nil,如果为空就不进行后面的赋值操作。
使用num1的时候直接赋值
var num1: Int? = 5
num1 = 7 //Optional(7)
num1? = 10 //Optional(10)
print(num1)
var num2: Int? = nil
num2? = 70
print(num2) //nil
num2 = 70 // nil
print(num2) //Optional(70)
可选项的本质
可选项的本质是enum类型
下面代码中Optional是个枚举,Wrapped既是泛型,也是关联值。
新的API
@frozen public enum Optional<Wrapped> : ~Copyable where Wrapped : ~Copyable {
case none
case some(Wrapped)
public init(_ some: consuming Wrapped)
}
老的API
public enum Optional<Wrapped> : ExpressibleByNilLiteral {
case none
case some(Wrapped)
public init(_ some: Wrapped))
}
func execGenerics() {
var age1: Int? = 10
var age2:Optional<Int> = 10
}
下面的age是等效的。互为语法糖
var age1: Int? = 10
var age2:Optional<Int> = 20
var age3:Optional<Int> = Optional.some(30)
var age4:Optional<Int> = .some(40)
var age5:Int? = .none
var age6:Int? = .some(50)
var age7:Int? = nil
var age8 = Optional<Int>.none
var age9 = Optional<Int>.some(70)
可选类型switch
下面的case let v?:中 ,相当于num = v 都是optional,不像if let 一样会自动解包。
let num: Int? = 30
switch num {
case let v?:
print(v) // 30
case nil:
print(num ?? 0)
}
let num1: Int? = nil
switch num1 {
case let .some(v):
print("some", v)
case .none:
print("none") // none
}
多重可选项
var age_: Int? = 10
var age: Int?? = age_
age = nil
var age0 = Optional.some(Optional.some(10))
age0 = .none
var age1: Optional<Optional> = .some(.some(10))
age1 = .none
var age2: Int?? = 10
var age3: Optional<Optional> = 10
© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
暂无评论...
