Swift基础

Swift进阶10:可选类型Optional & Equatab

2021-03-06  本文已影响0人  黑白森林无间道

Optional分析

Swift中的可选类型(Optional),用于处理值缺失的情况,有以下两种情况

这点可以通过Swift源码->Optional.swift源码(CMD+P,搜索Optional)源码来印证

@frozen
public enum Optional<Wrapped>: ExpressibleByNilLiteral {
    ......
  //为nil
  case none

    ......
  //有值
  case some(Wrapped)
  
  ......
}
var age: Int? = 10
等价于
var age1: Optional<Int> = Optional(10)

Optional使用模式匹配

//1、声明一个可选类型的变量
var age: Int? = nil
//2、通过模式匹配来匹配对应的值
switch age {
    case nil:
        print("age 是个空值")
    case .some(let val):
        print("age的值是\(val)")
}

Optional解包

【Optional解包】:因为是Optional类型,当我们需要从其中拿到我们想要的值时,需要对其进行解包,因为当前的可选项是对值做了一层包装的,有以下两种方式:

image
//可选项解包
var age: Int? = 10
//强制解包
print(age!)

//if let 可选绑定
if let value = age {
    print(value)
}

//guard let 可选绑定
guard let tmp = age else {
    print("age值为nil")
    return
}
print(tmp)

可选项绑定总结

unsafelyUnwrapped

这个和强制解包的内容是一致的,如下所示

//unsafelyUnwrapped 和强制解包内容是一致的
var age: Int? = 30
print(age!)
print(age.unsafelyUnwrapped)

//如果age1是nil
var age1: Int? = nil
//print(age1!)
print(age1.unsafelyUnwrapped)

age1nil的结果和强制解包一致,程序会崩溃

image image

这里的-O,是指target -> Build Setting -> Optimization Level设置成-O时,如果使用的是age1.unsafelyUnwrapped,则不检查这个变量是否为nil,

image

Equatable协议

在下面的例子中,可以通过==判断两个可选项是否相等,原因是因为Optinal在底层遵循了Equatable协议

//Equatable协议
var age: Int? = 10
var age1: Optional<Int> = Optional(10)

age == age1
extension Optional: Equatable where Wrapped: Equatable {
    
    ......
    
    @inlinable
  public static func ==(lhs: Wrapped?, rhs: Wrapped?) -> Bool {
    switch (lhs, rhs) {
    case let (l?, r?):
      return l == r
    case (nil, nil):
      return true
    default:
      return false
    }
  }
}

Swift标准库中的类型

在Swift中的类型,可以通过遵循Equatable协议来使用相等运算符(==)不等运算符(!=)比较两个值相等还是不相等,Swift标准库中绝大多数类型都默认实现了Equatable协议

例如下面的例子,对于Int类型来说,系统默认实现了 ==

image

结构体类型

对于自定义的类型,如果想实现 ==,应该怎么办呢?

image image

为什么呢?其根本原因是因为遵守了Equatable协议,系统默认帮我们实现了==方法

image image
image

Class类型

如果像Struct那么写,会报错,提示需要自己实现Equatable协议的方法

image
//class实现Equatable协议
class HTTeacher: Equatable {
    var age: Int
    var name: String
    
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    
    static func == (lhs: HTTeacher, rhs: HTTeacher) -> Bool {
        return lhs.age == rhs.age && lhs.name == rhs.name
    }
}
var t1 = HTTeacher.init(age: 18, name: "name")
var t2 = HTTeacher.init(age: 19, name: "name")
print(t1 == t2)

区分 == vs ===

Comparable协议

除了Equatable,还有Comparable协议,其中的运算符有:< 、<=、>=、> 、...、..<

public protocol Comparable : Equatable {
    static func < (lhs: Self, rhs: Self) -> Bool
    
    static func <= (lhs: Self, rhs: Self) -> Bool
    
    static func >= (lhs: Self, rhs: Self) -> Bool
    
    static func > (lhs: Self, rhs: Self) -> Bool
}
extension Comparable {
    public static func ... (minimum: Self, maximum: Self) -> ClosedRange<Self>
    ......
}

Struct重载 < 运算符

image

?? 空运算符

如果当前的变量为nil,可以在??返回一个nil时的默认值

//?? 空运算符
var age: Int? = nil
//?? 等价于 if let / guard let
print(age ?? 20)

//---打印结果
//20
<!--返回T-->
@_transparent//空运算符
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T)
    rethrows -> T {
  switch optional {
  case .some(let value):
    return value
  case .none:
    return try defaultValue()
  }
}

<!--返回T?-->
@_transparent
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T?)
    rethrows -> T? {
  switch optional {
  case .some(let value):
    return value
  case .none:
    return try defaultValue()
  }
}

从源码中分析,??只有两种类型,一种是T,一种是T?,主要是与 ?? 后面的返回值有关(即简单来说,就是??后是什么类型,??返回的就是什么类型),如下所示

image image image

可选链

可选链 则意味着 允许在一个链上来访问当前的属性/方法,如下所示

//可选链
class HTTeacher{
    var name: String?
    var subject: HTSubject?
}

class HTSubject {
    var subjectName: String?
    func test() { print("test") }
}

var s = HTSubject()
var t = HTTeacher()

//可选链访问属性
if let tmp = t.subject?.subjectName {
    print("tmp不为nil")
} else {
    print("tmp为nil")
}
//可选链访问方法
t.subject?.test()

运行结果如下,因为t.subject为nil,所以属性和方法都不会往下执行

image

总结

上一篇 下一篇

猜你喜欢

热点阅读