泛型方法中 T 和 Self 的区别
Difference between T and Self in generic methods
我正在编写一个名为 JSONDataInitializable
的协议,它将允许使用 JSONDecoder
.
从包含 JSON 的 Data
初始化值
由于 在初始化器中显式使用泛型,我在协议扩展中声明了一个通用的、类型不可知的辅助方法,稍后初始化器会调用它。
但是,我想出的不是一种,而是两种方法来编写这样的方法。
(1):
private static func initialize<T: JSONDataInitializable>(from jsonData: Data) throws -> T {
return try JSONDecoder().decode(T.self, from: jsonData)
}
(2):
private static func initialize(from jsonData: Data) throws -> Self {
return try JSONDecoder().decode(Self.self, from: jsonData)
}
您能解释一下这些方法之间的区别吗?他们似乎都产生相同的结果。
唯一可见的区别是第一个变体中的协议一致性部分。但是,这些方法是在协议扩展中声明的,因此仅适用于符合协议的类型。
UPD
这是完整的协议声明:
protocol JSONDataInitializable: Decodable {
init?(from jsonData: Data)
}
extension JSONDataInitializable {
init?(from jsonData: Data) {
do {
self = try Self.initialize(from: jsonData)
} catch {
print(error)
return nil
}
}
// (1)
private static func initialize<T: JSONDataInitializable>(from jsonData: Data) throws -> T {
return try JSONDecoder().decode(T.self, from: jsonData)
}
// ⬆⬆⬆
// OR
// ⬇⬇⬇
// (2)
private static func initialize(from jsonData: Data) throws -> Self {
return try JSONDecoder().decode(Self.self, from: jsonData)
}
}
假设我们有一个名为 User
的结构,它是 Decodable
。我们需要从 JSON 初始化 User
的值(存储为 Data
)。使用协议,初始化工作如下:
// Protocol conformance declaration
extension User: JSONDataInitializable { }
// JSON stored as Data
let networkData = ...
// Initialization
let john = User(from: networkData)
您使用 Self
的第二个实现符合您的要求。你想在协议中创建一个初始化器,你可以调用你想要初始化的类型。 Self
在协议函数中指的是你调用特定方法的类型。
另一方面,通用实现允许您初始化任何符合协议的类型,但在您的 init(from:)
方法中,您将 return 值分配给 self
,所以泛型类型参数 T
将被推断为 Self
。这使得没有必要使方法通用,因为在特定类型上,T
将始终是 Self
.
我正在编写一个名为 JSONDataInitializable
的协议,它将允许使用 JSONDecoder
.
Data
初始化值
由于
但是,我想出的不是一种,而是两种方法来编写这样的方法。
(1):
private static func initialize<T: JSONDataInitializable>(from jsonData: Data) throws -> T {
return try JSONDecoder().decode(T.self, from: jsonData)
}
(2):
private static func initialize(from jsonData: Data) throws -> Self {
return try JSONDecoder().decode(Self.self, from: jsonData)
}
您能解释一下这些方法之间的区别吗?他们似乎都产生相同的结果。
唯一可见的区别是第一个变体中的协议一致性部分。但是,这些方法是在协议扩展中声明的,因此仅适用于符合协议的类型。
UPD
这是完整的协议声明:
protocol JSONDataInitializable: Decodable {
init?(from jsonData: Data)
}
extension JSONDataInitializable {
init?(from jsonData: Data) {
do {
self = try Self.initialize(from: jsonData)
} catch {
print(error)
return nil
}
}
// (1)
private static func initialize<T: JSONDataInitializable>(from jsonData: Data) throws -> T {
return try JSONDecoder().decode(T.self, from: jsonData)
}
// ⬆⬆⬆
// OR
// ⬇⬇⬇
// (2)
private static func initialize(from jsonData: Data) throws -> Self {
return try JSONDecoder().decode(Self.self, from: jsonData)
}
}
假设我们有一个名为 User
的结构,它是 Decodable
。我们需要从 JSON 初始化 User
的值(存储为 Data
)。使用协议,初始化工作如下:
// Protocol conformance declaration
extension User: JSONDataInitializable { }
// JSON stored as Data
let networkData = ...
// Initialization
let john = User(from: networkData)
您使用 Self
的第二个实现符合您的要求。你想在协议中创建一个初始化器,你可以调用你想要初始化的类型。 Self
在协议函数中指的是你调用特定方法的类型。
另一方面,通用实现允许您初始化任何符合协议的类型,但在您的 init(from:)
方法中,您将 return 值分配给 self
,所以泛型类型参数 T
将被推断为 Self
。这使得没有必要使方法通用,因为在特定类型上,T
将始终是 Self
.