学习 swift
语言过程中,会不断发现 swift
一些匪夷所思的语法。学过之后,常常反问一句,真的有必要吗?
没学之前,谁会想到 self
和 Self
是不同的。
关键字 self
场景 1 前置 self.
前置 self.
是最常使用的场景,此时关键字 self
同其他语言的 this
关键字类似,可以代表编码过程中当前代码运行所属实例。
class Foo {
private var name: String = ""
init(_ name: String) {
self.name = name //属性名与参数名发生歧义,通过 self. 进行明确指定
}
func show() {
print("name = \(name)") //没有歧义时,直接使用属性名即可
}
}
需要注意的是,前置 self.
代表的是当前类型的实例对象。在类型定义中,如果前置 self.
出现在内嵌类型或匿名函数时,要注意其所指。这点和 es6 简明教程 - 令人崩溃的 this 有些类似。
在 es6 中, 关键字 this, 与函数、对象、类无关,只与执行期上下文有关.
extension Foo {
//增加一个计算属性 通过匿名函数进行赋值,内部访问 前置 self. 属性
var age: Int = {
//print(self.name) //在 swift 5.7 中会直接提示错误 无法找到 self 对象
return 25
}()
}
在 swift 5.7 中会直接提示错误 无法找到 self 对象。
场景 2 后置 .self
You can use the postfix self expression to access a type as a value. For example, SomeClass.self returns SomeClass itself, not an instance of SomeClass. And SomeProtocol.self returns SomeProtocol itself, not an instance of a type that conforms to SomeProtocol at runtime.
后置 .self
, 返回的是对应的 类型
(type), 而不是 实例
(instance).
最常见到的地方是在对象的反序列化操作中,如:
struct Foo: Codable {
let name: String
}
let decoder = JSONDecoder()
//返回值就是 Foo 类型实例
let json = """
{
"name": "Durian"
}
""".data(using: .utf8)!
//func decode<T>(T.Type, from: Data) -> T
let foo = try decoder.decode(Foo.self, from: json)
看看 decode 的函数定义,就可以了解到 Foo.self
代表的是 Foo
类型的元类型,
关键字 Self
第一次看见 Self 关键字时,我以为和 self 是一个东西,注意前置和后置就好了。可是,看看上下文,用 Self 的地方根本就不会出现前置后置符号 .
。
The Self type isn’t a specific type, but rather lets you conveniently refer to the current type without repeating or knowing that type’s name.
In a protocol declaration or a protocol member declaration, the Self type refers to the eventual type that conforms to the protocol.
class Foo {
private var name: String = ""
required init(_ name: String) { // 增加 required 关键字
self.name = name
}
func show() {
print("name = \(name)")
}
}
扩展一个单件属性:
extension Foo {
static var jay: Self {
Self("jay")
}
}
可见此处 Self
关键字就是类型 Foo
的一种简便的代码写法而已,本身并不会有其他特性。