Swift self, Self, ==, === 傻傻分不清楚?
本文首发于 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 。在掌握新特性的同时,不定期地去温习旧的基础知识,这样可以有效地保证自己的认知没有与现实脱节~
以上就是本文的全部内容,如有谬误,麻烦帮我指出。
如果你也有推荐阅读的内容,请留言告诉我,大家共同进步!谢谢~
Swift self, Self, ==, === 傻傻分不清楚?的更多相关文章
- JS魔法堂:属性、特性,傻傻分不清楚
一.前言 或许你和我一样都曾经被下面的代码所困扰 var el = document.getElementById('dummy'); el.hello = "test"; con ...
- MVP MVC MVVM 傻傻分不清
最近MVC (Model-View-Controller) 和MVVM (Model-View-ViewModel) 在微软圈成为显学,ASP.NET MVC 和WPF 的Prism (MVVM Fr ...
- Java:接口和抽象类,傻傻分不清楚?
01. 来看网络上对接口的一番解释: 接口(英文:Interface),在 Java 编程语言中是一个抽象类型,是抽象方法的集合.一个类通过继承接口的方式,从而来继承接口的抽象方法. 兄弟们,你们怎么 ...
- [转帖]十分钟快速理解DPI和PPI,不再傻傻分不清!
十分钟快速理解DPI和PPI,不再傻傻分不清! https://baijiahao.baidu.com/s?id=1605834796518990333&wfr=spider&for= ...
- OCA,OCP,OCM傻傻分不清?
可能大家知道OCA.OCP.OCM的关系是一个比一个难考,一个比一个含金量高,但是你知道具体的考试科目.考试方式.就业形势区别吗?不知道的话这篇通俗易懂的文章会让你一目了然. 区别一:含金量 ■OCA ...
- 学点经济学:M0、M1、M2、M3,傻傻分不清?(转载)
来源:http://t.10jqka.com.cn/pid_97006727.shtml 学点经济学:M0.M1.M2.M3,傻傻分不清? 25,508人浏览 2018-08-03 11:06 常听人 ...
- 【华为敏捷/DevOps实践】7. 敏捷,DevOps,傻傻不分清楚【华为云技术分享】
文:姚冬(华为云DevCloud首席技术布道师,资深DevOps与精益/敏捷专家,金融解决方案技术Leader,中国DevOpsDays社区核心组织者) 前言 敏捷是什么?DevOps是什么?两者有什 ...
- 傻傻分不清之 Cookie、Session、Token、JWT
傻傻分不清之 Cookie.Session.Token.JWT 什么是认证(Authentication) 通俗地讲就是验证当前用户的身份,证明“你是你自己”(比如:你每天上下班打卡,都需要通过指纹打 ...
- Shell中傻傻分不清楚的TOP3
Shell中傻傻分不清楚的TOP3 发布文章 近来小姐姐又犯憨憨错误,问组内小伙伴export命令不会持久化环境变量吗?反正我是问出口了..然后小伙伴就甩给了我一个<The Linux Comm ...
- ASCII、Unicode、UTF-8、UTF-8(without BOM)、UTF-16、UTF-32傻傻分不清
ASCII.Unicode.UTF-8.UTF-8(without BOM).UTF-16.UTF-32傻傻分不清 目录 ASCII.Unicode.UTF-8.UTF-8(without BOM). ...
随机推荐
- ES6学习 第三章 字符串的扩展
前言 本章主要是内容为是 ES6 对字符串的改造和增强. 本章记录字符串的扩展常用重点部分,不常用知识稍作记录. 本章原文链接: 字符串的扩展 模板字符串(template string) ES6字符 ...
- APB_AHB_AXI协议的简单介绍
一.AMBA概述 今天要介绍的三种嵌入式总线技术:APB.AHB.AXI,它们都属于AMBA 片上总线协议.所以,在介绍这几种总线技术之前,有必要先了解一下AMBA 片上总线协议是什么. AMBA ( ...
- IPFS 添加和管理文件
IPFS的文件有不同的模式 默认模式 默认模式下, 文件会被解析并存入blocks, 同时文件的结构被存入filestore, 因为IPFS是按内容寻址的文件系统, 在添加时最外层的目录名或文件名信息 ...
- React中的纯组件
React中的纯组件 React提供了一种基于浅比较模式来确定是否应该重新渲染组件的类React.PureComponent,通常只需要继承React.PureComponent就可以定义一个纯组件. ...
- 全流程点云机器学习(一)使用CloudCompare自制sharpNet数据集
前言 这不是高支模项目需要嘛,他们用传统算法切那个横杆竖杆流程复杂耗时很长,所以想能不能用机器学习完成这些工作,所以我就来整这个工作了. 工欲善其事,必先利其器,在正式开始之前,我们先要搞懂如何切分数 ...
- 实操开源版全栈测试工具RunnerGo安装(一)
Docker版安装文档 一.环境要求 1.1 部署服务器要求 操作系统:任何支持 Docker 的 Linux x86 CPU内存:最低要求 4C8G,推荐 8C16G 网络要求:可访问互联网 ...
- 【Android 逆向】【ARM汇编】 事前更新和事后更新
1. 事前更新,事后更新,不更新 不更新 ldr R4, [R1, R2, lsl #1] 相当于 R4 = *(R1 + R2 << 2^1) 之后 R1.R2的值时没有变化的 事前更新 ...
- Unity学习笔记--数据持久化Json
JSON相关 json是国际通用语言,可以跨平台(游戏,软件,网页,不同OS)使用, json语法较为简单,使用更广泛.json使用键值对来存储. 认识json文件 //注意字典类型存储时,键是以st ...
- day05---系统的重要文件(2)
回顾 /etc/sysconfig/network-scripts/ifcfg-eth0 网卡配置文件 TYPE=Ethernet BOOTPROTO=none NAME=eth0 DEVICE=et ...
- gorm整理
目录 1. 约定 2. 结构体标签 3. 创建记录 4. 更新 5.删除 6. 查询 7.关联 8.链式操作 9.范围 10.多个立即执行方法的注意事项 11.错误处理 12.钩子 13.事务 14. ...