- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
如何在隐藏实现 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
需要能够相互比较对象,以解决两个事物具有相同哈希值的冲突。它如何将 HashyStruct
与 HashyClass
进行比较?它不知道调用哪个函数来比较两个对象。它不知道是否调用 HashyStruct
或 HashyClass
上的 hashValue
。
如果你想在运行时动态地执行它,你实际上可以实现它。您实现的“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/
有没有人写过一个通用函数以便hash可以为自定义数据类型自动生成函数(使用 deriving 机制)?有几次,我写了以下样板, data LeafExpr = Var Name | Star deri
我们如何让 SwiftUI 对象,尤其是 Image,符合 Hashable 协议(protocol)? 我知道它们符合 Equatable 协议(protocol),所以主要问题是如何获取哈希值,或
我需要某种薄包装对象来标记字典键,例如: d = { Required('name'): str, Optional('age'): int, } 并且这些包装器的行为应该像被包装的对象(比较
我实现了下面的类: class Table : Hashable { var uid : Int var timeRemaining : Int? var curren
有时我编写的函数的参数可以是任何类型,只要它是 hashable。 - 例如,因为我的函数将其添加到集合中或将其用作字典键。 有没有一种方法可以使用 Python 3.5 中引入的 PEP 484 类
这个问题已经有答案了: Make struct Hashable? (2 个回答) 已关闭 5 年前。 我希望创建一个仅保存结构的唯一实例的数组: var vowelSet: Set 这是我的结构
protocol Component {} struct Container { let map: [Component: Component] } 在上面的代码中,如何指定 map 的键可以
我有一个自定义控件,它使用数据源来获取项目(就像 NSTableView 所做的那样)。数据源可以返回任何类型,只要它是可哈希的。这些项目用作私有(private)字典中的键。 控件(自定义 View
在 Hashable 内部我们可以看到: /// Hash values are not guaranteed to be equal across different executions of /
在 Xcode 10 和 Swift 4.2 中,还有其他类型符合 Hashable,只要它们的元素也符合 Hashable(Array 、字典等)。 我目前在我的项目中有一些代码为 Swift 4.
我想使用自定义枚举数组作为字典键,但我很难弄清楚如何使数组符合 Hashable。编译器告诉我 [Symbol] 不符合 Hashable。我需要做什么才能编译它? 我搞砸了对 Array 的扩展,其
假设我有一个名为 LivingCreature 的类以及继承自它的其他类: 人类 狗 外星人 这就是我想要完成的: let valueForLivingCreature = Dictionary 然后
我有一些结构符合的基本协议(protocol)(模型)。它们也符合 Hashable protocol Model {} struct Contact: Model, Hashable { v
考虑以下代码: #!/usr/bin/env python3.7 from typing import NamedTuple, Set class Person(NamedTuple): na
我有一个自定义的映射类,如下所示。 class UserSaved { var Id : String var UserName : String var
它在 java 中很容易完成 - 哈希码似乎是指向对象或其他东西的指针。为什么 swift 没有为我们提供同样的舒适感,而是要求我们自己定义函数? 最佳答案 哈希码似乎是指向对象或其他东西的指针。 在
我正在尝试在 Swift 中创建一个函数,它将一个字符串字典作为参数,并返回一个字符串元组。我希望字典中的键值对是可选的,因为如果它返回的元组中的值之一是“nil”,我不希望我的程序崩溃。 func
我正在尝试修复 RayWenderlich 网站上不再受支持的旧教程。该警告出现在三个文件中,Chain.swift、Cookie.swift 和 Swap.swift,来自“如何使用 SpriteK
如何在隐藏实现 Hashable 的具体类型的地方返回 [Hashable: Any]? Swift 有两种类型的协议(protocol):可以用作类型的协议(protocol)和只能用作类型约束的协
假设我有一个基类“Person”,我想将其添加到一个集合(列表)中,因此需要符合 Hashable 和 Equatable: class Person : Equatable, Hashable {
我是一名优秀的程序员,十分优秀!