本文首发于 Ficow Shen's Blog,原文地址: Swift self, Self, ==, === 傻傻分不清楚?。
内容概览
-
前言
-
self 和 Self
-
== 和 ===
-
总结
前言
在2014年开源之后,Swift就在飞速地茁壮成长,内涵也越来越丰富。
对于实际使用Swift的人来说,概念多了就比较容易混淆????,然后就会导致开发效率低下。毕竟,你需要去查这些概念的正确定义,或者你需要去写代码进行验证。self, Self, ==, === 就是比较典型的例子。
在面试别人的过程中,我发现有很多朋友分不清楚这些概念。所以,我打算根据我自己的理解来梳理一下这些概念,希望能够帮大家少走一些弯路。????????????
self 和 Self
实例中的 self
首先,最简单的肯定是实例中的 self 了:
如上图所示,Xcode 会告诉你这个 self 属于 TestClass 类型。
类型中的 self :
如上图所示,Xcode 会告诉你这个 self 是 TestClass.Type 类型。稍等一下,.Type 是什么东西?
从字面意思去理解,这个 self 是 TestClass 这个类型本身。
如果为该类型定义一个静态常量(static let ),我们就可以在类型的静态方法(static func )中去访问这个静态常量。因为,它们都属于这个类型本身。self.classLet 也就是在访问 TestClass 这个类型本身的常量 classLet 。
实体类型(concrete type)中的 Self
请看,我们可以直接通过 Self 去访问类型上的属性:
但是,这个 Self 不等于 self 。
上图中的 print 函数会打印 true 。为什么呢?
请推测一下,print(TestClass.self == self) 会打印 true 还是 false ?
请不要停止思考,更有意思的来了????:
请问,这些 print 会分别打印什么内容?
好吧,结果是 3 行 true 。所以, 这个 Self 等同于当前这个实体类型,对吗?
抱歉,不对!!!???? 根据 官方文档 的内容,这个 Self 的值等于 type(of: self) 。也就是说,这个值是动态获取的!
现在,让我们来看一个示例:
class TestClass {
static let classLet = 0
let instanceLet = classLet // 不能写成 self.classLet
var instanceVar = classLet
lazy var instanceLazyVar = Self.classLet // 不能写成 self.classLet
}
如果需要用类型中的属性来初始化实例中的属性,就可以参考上面这种方法。注意,不能写成 let instanceLet = self.classLet 。这样写会出现编译错误,self 是未定义的。
如果使用懒加载的属性,要注意区分 self 和 Self 。因为实例已经完成了初始化,此时 self 是有效的。
如果将 Self 用在协议中,比如:
protocol TestProtocol {
func getSelf() -> Self
}
class TestBaseClass: TestProtocol {
func getSelf() -> Self {
return self
}
}
class TestSubclass: TestBaseClass {
override func getSelf() -> Self {
return self
}
}
let base: TestBaseClass = TestBaseClass()
let sub: TestSubclass = TestSubclass()
此时,Self 是最终实现协议的那个类型。
== 和 ===
==
- 是
Equatable 协议中定义的方法:static func == (lhs: Self, rhs: Self) -> Bool ;
- 否定形式:
!= ;
- 支持自定义比较,规则可以由开发者自行定义比较的规则;
示例:
class MyType: Equatable {
let id: UUID
let name: String
init(id: UUID, name: String) {
self.id = id
self.name = name
}
static func == (lhs: MyType, rhs: MyType) -> Bool {
// lhs: left-hand side, rhs: right-hand side
// 也可以是: return lhs.id == rhs.id,规则由你来定义
return lhs.id == rhs.id && lhs.name == rhs.name
}
}
// 还可以这样定义:
class MyType: Equatable {
let name: String
init(name: String) {
self.name = name
}
static func == (lhs: MyType, rhs: MyType) -> Bool {
// ObjectIdentifier 不支持值类型
// 也可以这样比较: return lhs === rhs
return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
}
}
===
- 比较的是指针,所以只能用于比较引用类型;
- 否定形式:
!== ;
- 不支持开发者自定义比较的规则;
示例:
NSObject() === NSObject()
相关文档: Equivalence Operators(==) Identity Operators(===)
总结
这些是比较常用而且比较基础的语法知识点,我们要争取理解到位,否则就会影响到开发效率。
这是 Swift 的 Revision History(文档修订历史),建议大家多关注。比如 SwiftUI 中最常见的 some 关键字就是在 Swift 5.1 中新增的 Opaque Types 。在掌握新特性的同时,不定期地去温习旧的基础知识,这样可以有效地保证自己的认知没有与现实脱节~
以上就是本文的全部内容,如有谬误,麻烦帮我指出。
如果你也有推荐阅读的内容,请留言告诉我,大家共同进步!谢谢~ ????
|
请发表评论