Swift 如何使用Xcode 10中可用的API使枚举符合Hashable?
在我的Swift 4.2.1代码中,我有以下枚举:Swift 如何使用Xcode 10中可用的API使枚举符合Hashable?,swift,xcode10,swift4.2,hashable,Swift,Xcode10,Swift4.2,Hashable,在我的Swift 4.2.1代码中,我有以下枚举: enum MyEnum { case caseOne(Int) case caseTwo(String) case caseThree } 它符合equalable: extension MyEnum: Equatable { static func == (lhs: MyEnum, rhs: MyEnum) -> Bool { switch (lhs, rhs) {
enum MyEnum {
case caseOne(Int)
case caseTwo(String)
case caseThree
}
它符合equalable
:
extension MyEnum: Equatable {
static func == (lhs: MyEnum, rhs: MyEnum) -> Bool {
switch (lhs, rhs) {
case (.caseOne, .caseOne), (.caseTwo, .caseTwo), (.caseThree, .caseThree):
return true
default:
return false
}
}
}
我需要使其符合可哈希的,这就是我添加扩展的原因:
extension MyEnum: Hashable {
var hashValue: Int {
switch self {
case .caseOne:
return 1
case .caseTwo:
return 2
case .caseThree:
return 3
}
}
}
现在我想迁移到Xcode 10中提供的新API。我删除了hashValue
的实现,并将哈希的实现添加到:)
:
你能告诉我我是否正确地切换到了新的API吗?我使用这个测试,如果一切正常,它会打印两次true
:
var testDictionary = [MyEnum: Int]()
testDictionary[.caseOne(100)] = 100
testDictionary[.caseOne(1000)] = 1000
testDictionary[.caseTwo("100")] = 100
testDictionary[.caseTwo("1000")] = 1000
let countCaseOne = testDictionary.reduce(0) {
if case .caseOne = $1.key {
return $0 + 1
}
return $0
} == 1
print(countCaseOne) // true
let countCaseTwo = testDictionary.reduce(0) {
if case .caseTwo = $1.key {
return $0 + 1
}
return $0
} == 1
print(countCaseTwo) // true
无需手动实现Hashable
一致性,编译器可以自动合成特定enum
(其中所有具有关联值的案例都有一个Hashable
关联值)。您只需要声明一致性
enum MyEnum: Hashable {
case caseOne(Int)
case caseTwo(String)
case caseThree
}
// You don't even need to write `: Equatable`, since automatic Hashable conformance takes care of Equatable too, I just left it there for clarity
extension MyEnum: Equatable {
static func == (lhs: MyEnum, rhs: MyEnum) -> Bool {
switch (lhs, rhs) {
case (.caseOne, .caseOne), (.caseTwo, .caseTwo), (.caseThree, .caseThree):
return true
default:
return false
}
}
}
您可以按照另一个答案中的建议使用自动生成的Hashable
一致性(在您的类型不包含任何非Hashable
类型的日期的情况下)
但在一般情况下,您可以这样做(自动生成的代码可能也是这样):
你想知道什么?在我看来这是正确的。@Sandeep在教程中,我在hash(into:)
的实现中看到了类似于hasher.combine(self.property)
的东西。我没有找到enum的示例。这就是为什么我想知道我的实现是否正确。顺便说一下,你不必自己实现这个方法。语言根据您的属性自行执行。如果enum的所有关联值都是可哈希的(或没有)。@user28434是的,这就是为什么我提到了OP的特定enum,但我会编辑我的答案,使其更一般。谢谢您的回答。但是我忘了写MyEnum
包含=
的实现,请检查我更新的答案。@RomanPodymov这没有什么区别,您仍然可以使用自动哈希表
一致性并覆盖自动合成的=
方法。检查我的最新答案。顺便说一句,你确定你不关心关联值的相等性吗?@DávidPásztor在我的例子中,我不需要检查关联值。如果没有实现散列(into:)
的话,我的测试的输出是真
/真
,真
假
或假
/真
。谢谢你的回答。但是为什么我可以跳过combine
来处理.casetree
?因为hasher
已经有了一些初始状态(我们称之为seed
),然后combine(:)
对hasher
状态(seed
初始)执行一些函数,然后执行组合值,结果将替换哈希器的状态。然后,hasher
的状态转换为hash
函数结果,该结果可通过hashValue
属性访问。因此,即使您根本不进行组合,您仍然会得到一个结果。Ofc,如果你有多个案例
而没有关联值
,你最好将其与一些常量
结合起来,否则这些案例的哈希值将是相同的。请检查我编辑过的答案,我将=
添加到MyEnum
。因为我不需要检查关联值。@RomanPodymov,嗯,如果您不需要它来进行散列,那么您可以使用答案中的散列(into:)
实现。
enum MyEnum: Hashable {
case caseOne(Int)
case caseTwo(String)
case caseThree
}
// You don't even need to write `: Equatable`, since automatic Hashable conformance takes care of Equatable too, I just left it there for clarity
extension MyEnum: Equatable {
static func == (lhs: MyEnum, rhs: MyEnum) -> Bool {
switch (lhs, rhs) {
case (.caseOne, .caseOne), (.caseTwo, .caseTwo), (.caseThree, .caseThree):
return true
default:
return false
}
}
}
extension MyEnum: Hashable {
func hash(into hasher: inout Hasher) {
switch self {
case .caseOne(let value):
hasher.combine(value) // combine with associated value, if it's not `Hashable` map it to some `Hashable` type and then combine result
case .caseTwo(let value):
hasher.combine(value) // combine with associated value, if it's not `Hashable` map it to some `Hashable` type and then combine result
case .caseThree:
// you can `combine` with some `Hashable` constant, but here it's ok just to skip
break
}
}
}