我有一个结构,需要解码和散列。此结构具有Protocol类型的属性。根据类型,在结构中填充协议的具体值。但是,我如何使这个结构可散列化,而不使协议可散列化(这使它成为一个不能直接使用的通用协议)?
enum Role: String, Decodable, Hashable {
case developer
case manager
....
}
protocol Employee {
var name: String { get }
var jobTitle: String { get }
var role: Role { get }
}
struct Manager: Employee, Hashable {
let name: String
let jobTitle: String
let role: Role = .manager
....
}
struct Developer: Employee, Hashable {
let name: String
let jobTitle: String
let role: Role = .developer
let manager: Employee // Here is the problem
static func == (lhs: Developer, rhs: Developer) -> Bool {
lhs.name == rhs.name &&
lhs.jobTitle == rhs.jobTitle &&
lhs.role == rhs.role &&
lhs.manager == rhs.manager // Type 'any Employee' cannot conform to 'Equatable'
}
func hash(into hasher: inout Hasher) {
hasher.combine(name)
hasher.combine(jobTitle)
hasher.combine(role)
hasher.combine(manager) // Instance method 'combine' requires that 'H' conform to 'Hashable'
}
}
这有多个问题:
1.为了使一个属性Hashable/Equatable,我们需要编写包含所有属性的==
和hash
函数。
1.即使我们这样做了,仍然有一个问题,即协议不是Hashable/Equatable。
有没有其他或正确的方法来做到这一点?
1条答案
按热度按时间b1zrtrql1#
我的意思是,你已经做了这个内部。你有一个枚举,它与结构体有1:1的对应关系。这表明枚举应该包含数据而不是使用协议:
这有点乏味,因为每个属性在每种情况下都需要一个
switch
。如果属性的数量有限,这很好,但是如果属性列表很大并且不断增长,这可能会很烦人。由于员工都非常相似,另一种方法是将不同的内容放入他们的角色中。(我假设这是一个通用的例子,因为在大多数组织中,经理也有经理。这可能是一个重新思考你的类型的时候,并决定经理和开发人员是否真的是不同的东西。如果
developer.manager
可以成为开发者,为什么是两种类型?)但您也可以使用协议保留当前的设计。在您的示例中,不需要
any Employee
成为Equatable。您需要能够将一个Employee与任意其他Employee进行比较。那不是一回事以这种方式扩展您的Employee,允许它与任意其他Employee进行比较(这与Equatable不同,Equatable只是意味着一个类型可以与Self进行比较)。
这样,您的
==
实现看起来像:Hashable的情况甚至更简单,因为Hashable没有自己的关联类型。所以你可以把它作为一个要求: