Swift self, Self, ==, === 傻傻分不清楚?

 

本文首发于 Ficow Shen's Blog,原文地址: Swift self, Self, ==, === 傻傻分不清楚?

 

内容概览

  • 前言

  • selfSelf

  • =====

  • 总结

 

前言

 

在2014年开源之后,Swift就在飞速地茁壮成长,内涵也越来越丰富。

对于实际使用Swift的人来说,概念多了就比较容易混淆😨,然后就会导致开发效率低下。毕竟,你需要去查这些概念的正确定义,或者你需要去写代码进行验证。self, Self, ==, === 就是比较典型的例子。

在面试别人的过程中,我发现有很多朋友分不清楚这些概念。所以,我打算根据我自己的理解来梳理一下这些概念,希望能够帮大家少走一些弯路。🌟🌟🌟

 

selfSelf

 

实例中的 self

首先,最简单的肯定是实例中的 self 了:

图片alt

如上图所示,Xcode 会告诉你这个 self 属于 TestClass 类型。

 

类型中的 self

图片alt

如上图所示,Xcode 会告诉你这个 selfTestClass.Type 类型。稍等一下,.Type 是什么东西?
从字面意思去理解,这个 selfTestClass 这个类型本身。

图片alt

如果为该类型定义一个静态常量(static let),我们就可以在类型的静态方法(static func)中去访问这个静态常量。因为,它们都属于这个类型本身。self.classLet 也就是在访问 TestClass 这个类型本身的常量 classLet

 

实体类型(concrete type)中的 Self

请看,我们可以直接通过 Self 去访问类型上的属性:

图片alt

但是,这个 Self 不等于 self

图片alt

上图中的 print 函数会打印 true。为什么呢?

图片alt

请推测一下,print(TestClass.self == self) 会打印 true 还是 false

请不要停止思考,更有意思的来了😹:
图片alt

请问,这些 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 是未定义的。
如果使用懒加载的属性,要注意区分 selfSelf。因为实例已经完成了初始化,此时 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 。在掌握新特性的同时,不定期地去温习旧的基础知识,这样可以有效地保证自己的认知没有与现实脱节~

以上就是本文的全部内容,如有谬误,麻烦帮我指出。
如果你也有推荐阅读的内容,请留言告诉我,大家共同进步!谢谢~ 🤗

 
 

posted @ 2020-08-12 23:04  Ficow  阅读(2996)  评论(0编辑  收藏  举报