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). ...
随机推荐
- NC20684 wpy的请求
题目链接 题目 题目描述 "题目名称只是吸引你来做题的啦,其实和题目没什么卵关系:o(* ̄▽ ̄*)o" -- 历史--殿堂 wpy移情别恋啦,他不喜欢spfa了,现在他喜欢使用di ...
- NC210520 Min酱要旅行
题目链接 题目 题目描述 从前有个富帅叫做Min酱,他很喜欢出门旅行,每次出门旅行,他会准备很大一个包裹以及一大堆东西,然后尝试各种方案去塞满它. 然而每次出门前,Min酱都会有个小小的烦恼.众所周知 ...
- 【解决方案】Java 互联网项目如何防止集合堆内存溢出(一)
目录 前言 一.代码优化 1.1Stream 流自分页 1.2数据库分页 1.3其它思考 二.硬件配置 2.1云服务器配置 三.文章小结 前言 OOM 几乎是笔者工作中遇到的线上 bug 中最常见的, ...
- MASM32 - PlaySound的实现
MASM安装教程: https://blog.csdn.net/u010486308/article/details/105495848 代码参考: .model flat, stdcall opti ...
- pyqt5中通过pycharm配置designer(win和mac都适用,修改下designer目录路径即可)
安装 pip install PyQt5 -i https://pypi.douban.com/simple pip install PyQt5-tools -i https://pypi.douba ...
- 07-Redis系列之-双写一致性,缓存详解和优化点
双写一致性 双写一致性指的是当我们更新了数据库的数据之后redis中的数据也要同步去更新. redis和mysql数据同步方案 先更新缓存,再更新数据库(然并软...) 先更新数据库,再更新缓存(一般 ...
- 【LeetCode贪心#03】最大子序和
最大子序和 力扣题目链接 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 子数组 是数组中的一个连续部分. 示例 1: 输入:nums = ...
- Java面向对象之内部类的几类使用场景
介绍 Java内部类是一种特殊的类,它定义在另一个类的内部.内部类提供了许多有用的特性,包括访问外部类的私有成员.隐藏实现细节以及实现回调接口等.以下是Java内部类的一些常用场景及其举例说明: 回调 ...
- Gitlab中的打包作业完成后,更新http服务器里的版本号文件
背景 在.gitlab-ci.yml里面,我们有4个场景 dotnet build.dotnet pack和dotnet push 单元测试 SSH到http服务器,更新对应的版本号文件里面的版本数字 ...
- 【Azure Developer】Visual Studio 2019中如何修改.Net Core应用通过IIS Express Host的应用端口(SSL/非SSL)
问题描述 在VS 2019调试 .Net Core Web应用的时,使用IIS Express Host,默认情况下会自动生成HTTP, HTTPS的端口,在VS 2019的项目属性->Debu ...