本文首發於 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
。在掌握新特性的同時,不定期地去溫習舊的基礎知識,這樣可以有效地保證自己的認知沒有與現實脫節~
以上就是本文的全部內容,如有謬誤,麻煩幫我指出。
如果你也有推薦閱讀的內容,請留言告訴我,大家共同進步!謝謝~ 🤗