gpt4 book ai didi

swift - 在 Swift 中隐藏 Hashable

转载 作者:可可西里 更新时间:2023-11-01 02:17:22 30 4
gpt4 key购买 nike

如何在隐藏实现 Hashable 的具体类型的地方返回 [Hashable: Any]

Swift 有两种类型的协议(protocol):可以用作类型的协议(protocol)和只能用作类型约束的协议(protocol)。虽然这很强大,但也很不幸。这意味着某些类型的信息隐藏不是直接可能的。

我能想到的唯一解决方案是使用 thunk:

struct Hash: Hashable {
private let value: Any
private let equals: Hash -> Bool

init<H: Hashable>(_ h: H) {
self.value = h
self.hashValue = h.hashValue
self.equals = { ($0.value as! H) == h }
}

let hashValue: Int
}

func ==(lhs: Hash, rhs: Hash) -> Bool {
return lhs.equals(rhs)
}

也许有一天 Swift 会为我们创建这样的 thunk。这毕竟是编译器的目的之一。

这是唯一的方法吗?我错过了什么吗?

最佳答案

这背后的原因是像 Hashable 这样的快速协议(protocol)可以应用于所有不同的类型,而不仅仅是类。

假设我们有两种不同的类型:一种占用 8 位内存的结构和一种指向堆上某个内存块的指针的类。

struct HashyStruct : Equatable, Hashable {
let smallNumber: UInt16
var hashValue: Int {
return Int(smallNumber)
}
}
func ==(lhs: HashyStruct, rhs: HashyStruct) -> Bool {
return lhs.smallNumber == rhs.smallNumber
}


class HashyClass : Equatable, Hashable {
let number: UInt64
init(number: UInt64) {
self.number = number
}
var hashValue: Int {
return Int(number)
}
}
func ==(lhs: HashyClass, rhs: HashyClass) -> Bool {
return lhs.number == rhs.number
}

这两种类型都是Hashable,那么为什么我们不能有这样的字典:

let anyHashable: [Hashable:Any] = [HashyStruct(smallNumber: 5) : "struct", HashyClass(number: 0x12345678):"class"]

error: using 'Hashable' as a concrete type conforming to protocol 'Hashable' is not supported error: protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements

Dictionary 需要能够相互比较对象,以解决两个事物具有相同哈希值的冲突。它如何将 HashyStructHashyClass 进行比较?它不知道调用哪个函数来比较两个对象。它不知道是否调用 HashyStructHashyClass 上的 hashValue

但是 Objective-C 做到了...

如果你想在运行时动态地执行它,你实际上可以实现它。您实现的“thunk”确实具有那种动态行为,但它会带来在大多数情况下您不需要承受的性能损失。

更多有趣的哈希表细节,这些细节不是特别重要,但可以帮助您理解

我假设您知道如何将散列表实现为固定大小的数组,以及如何将散列值映射到有限数量的可能存在冲突的存储桶。

Dictionary 分配一 block 内存来存储它的对象;让我们给它 4 个部分,每个部分 64 个字节(64 位机器上指针的大小)。

| 64 字节 | 64 字节 | 64 字节 | 64 字节 |

当您添加哈希值为 1 和 6 = 2 % 4 的两个项目时,您将获得以下哈希表:

|空 |第 1 项 |第 2 项 |空 |

一切都很好;我们可以将任意数量的指针对象放入我们的表中,这将适用于类。但是在 swift 中我们有结构——HashyStruct 只有 16 位。如果我们为存储 HashyStruct 的字典提供相同数量的内存,那么我们可以在哈希集中存储 16 个而不是 4 个项目。

| 16 字节 | 16 字节 | 16 字节 | 16 字节 | 16 字节 | 16 字节 | 16 字节 | 16 字节 | 16 字节 | 16 字节 | 16 字节 | 16 字节 | 16 字节 | 16 字节 | 16 字节 | 16 字节 |

只要编译器知道类型的大小,我们就可以在哈希表中拥有我们想要的任何类型。但是当我们有两种不同的类型时...???

| 4 个结构 |第 1 项 |第 2 项 |空 |

你得到一个没有意义的哈希表。编译器不知道数组中项目的大小,因此无法为它们编制索引。

让 swift 变得伟大的很多原因在于您不受限于分配在堆上的类和对象。默认情况下,它会为您提供良好的性能,并且您可以根据需要选择动态行为。

关于swift - 在 Swift 中隐藏 Hashable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35953203/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com