swift进阶十四:Optional & Equatable &
上一节,我们介绍了闭包,本节,我们介绍:
- Optional
- Equatable
- Comparable
- 访问控制(private、fileprivate、internal、public、open)
1. Optional
Optional
是enum
结构,包含some
和none
两个case项。是一个包含值
或nil
的类型
。
(所以Optional
类型size
就是enum
的大小
。 2个case
的enum
本身大小为1
,加上最大
case关联内容
(Wrapped类型)大小(如: Optional<String>、Optional<Int>))
public enum Optional<Wrapped>: ExpressibleByNilLiteral {
case none
case some(Wrapped)
}
1.1 创建:
// 快捷创建
var age: Int? = 10
// 普通创建
var name: Optional<String> = "ht"
- 打印结果为
Optional类型
image.png
1.2 使用:
1.2.1 枚举方式
- 因为
Optional
本身是enum
类型,所以可使用switch
来模式匹配
:
var age: Int? = 10
switch age {
case .some(let num):
print("age为\(num)")
case .none:
print("值为空")
}
1.2.2 解包
涉及到Optional
可选类型,我们就必须解包
,因为我们关注的更多是some值
。
- 但是每次
switch
处理,会让我们代码量增大
的同时,影响阅读体验
(因为我们实际只关心some值) - 以下是
三种解包
方式(推荐第二、第三种):
1. !强解包
非常不建议
使用强解包
。因为如果遇到值
为nil
,程序直接crash
。
- 很多都说使用
!
强解包,表示程序员
对自己的代码
足够自信
,并愿意承担
crash结果
。- 我想说的,
真实业务
场景下,作为开发者
,你必须保证
你的代码
足够健壮
,即便一定不会
为nil
,也不要
用! 强解包
。- 因为你
不确定
这份代码逻辑
以后会不会被他人改动
。所以我建议所有! 强解包
的场景,可以选择性使用Assets断言
,再使用下面第二
、第三种
方式。
2. if-let
-
if-let
可以配合else
使用,也可以直接在if
中添加return
,表示后续代码都是else场景下
,节省了else
的{}
,提高代码可读性
var age: Int? = nil
// 可以配合return使用, 省了else的{}
//if let value = age {
// print("value \(value)")
// return
//}
if let value = age {
print("value \(value)")
} else {
print("age 为 nil")
}
3 guard-let
guard-let
是具备守护功能
,它必须搭配return
使用,排除异常
情况,守护guard(作用域)
之后的代码
。
-
guard
中的条件
,如果不满足
,执行guard
内的代码后return
,guard(作用域)
之后的代码,一定是全部满足guard
条件的。
image.png
if-let
和guard-let
的使用建议
实际开发过程中,我们希望代码
从上至下
能清晰表达主线流程
。
guard-let
一般用于处理非主线
异常情况,直接return
出去,守护
主线代码。
if-let
一般用于处理主线
重要场景。
if-let
创建的内容,仅在if 作用域内
可访问。guard-let
创建的内容,是供guard 作用域外
访问。
2. Equatable
Swift
中的类型,可以通过遵循Equatable
协议来使用相等运算符(==)
和不等运算符(!=)
。
2.1 绝大多数类型
默认实现Equatable
协议
image.png
2.2 struct(值类型)
-
值类型
支持直接比较
,所以只需要
遵循Equatable
协议,就自动
实现(==)
和(!=)
image.png
2.3 class(引用类型)
-
引用类型
需要先遵循Equatable
协议,再手动
实现(==)
和(!=)
image.png
2.4 struct
有引用类型属性
(值类型+引用类型)
-
值类型
中包含引用类型
的实例
。必须实现引用类型
的Equatable (==)
函数,会根据Equatable (==)
进行判断:
image.png
2.5 Optional属性
-
可选值
属性,需要先拓展Optianl
的==
比较方式:
image.png
2.6 ==
与 ===
-
==
用来检验值
是否相等
,需要遵循Equatable
协议。也就是equal to
-
===
是用来检验两个对象
是否是同一个实例
对象(内存地址
是否相等
)。不支持值类型
,仅支持类实例(AnyObject?)
使用。
@inlinable public func === (lhs: AnyObject?, rhs: AnyObject?) -> Bool
@inlinable public func !== (lhs: AnyObject?, rhs: AnyObject?) -> Bool
image.png
3. Comparable
Comparable
协议继承了Equatable
协议,并多支持了其他比较方式
。
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>
@inlinable public static func > (lhs: Self, rhs: Self) -> Bool
@inlinable public static func <= (lhs: Self, rhs: Self) -> Bool
@inlinable public static func >= (lhs: Self, rhs: Self) -> Bool
public static func ..< (minimum: Self, maximum: Self) -> Range<Self>
prefix public static func ..< (maximum: Self) -> PartialRangeUpTo<Self>
prefix public static func ... (maximum: Self) -> PartialRangeThrough<Self>
postfix public static func ... (minimum: Self) -> PartialRangeFrom<Self>
}
image.png
4. 访问控制(private、fileprivate、internal、public、open)
-
OC
中很少接触
这个概念,Swift
中针对源文件
和模块
的代码,提供了不同程度
的访问控制
:
访问级别从低到高
依次是:
private
<fileprivate
<internal
<public
和open
-
private
: 访问级别仅在当前定义
的作用域内
class HTPerson {
private var age = 10
}
HTPerson().age // 访问不到age
利用private权限
,我们swift
的单例
正规写法为:
class HTPerson {
static let sharedInstance = HTPerson()
private init() {} // 外界无法调用init方法
}
filePrivate
: 访问级别仅在当前定义
的文件内
-
Internal
:默认访问级别
。允许模块中
的任意文件
访问(模块外不支持访问) (import的都是模块) public
: 开放式访问,允许任何模块
的任何文件
访问,但只支持定义模块内
继承和子类重写open
: 开放式访问,最不受限制,允许任何模块
的任何文件
访问、继承和子类重写
本节知识较简单,所以相关SIL分析
就没罗列
了。Optional
和访问控制
的使用频次
很高
。下一节,分析协议
和泛型