gpt4 book ai didi

swift - 检查 Hashable 一致性

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

我有一些结构符合的基本协议(protocol)(模型)。它们也符合 Hashable

protocol Model {}
struct Contact: Model, Hashable {
var hashValue: Int { return ... }
static func ==(lhs: Contact, rhs: Contact) -> Bool { return ... }
}
struct Address: Model, Hashable {
var hashValue: Int { return ... }
static func ==(lhs: Address, rhs: Address) -> Bool { return ... }
}

我有一个函数,它接受一个符合模型 ([Model]) 的对象数组。如何将 [Model] 传递给需要 Hashables 的函数而不使 Model Hashable?

func complete(with models: [Model]) {
doSomethingWithHashable(models) //can't do this
}
func doSomethingWithHashable <T:Hashable>(_ objects: [T]) {
//
}

我正在努力避免这种情况

protocol Model: Hashable {}
func complete<T:Model>(with models: [T]) {
runComparison(models)
}

因为当我执行此操作时得到“模型不能用作通用约束...”

protocol SomethingElse {
var data: [Model] { get }
}

最佳答案

你的代码的问题是你在谈论 Model ,它 promise 什么关于Hashable一致性。正如您所指出的,将此告诉编译器的问题(即从 Model 派生 Hashable )是您随后失去了根据符合 Model 的异构类型进行对话的能力。 .

如果你根本不关心Model首先一致性,你可以只使用标准库的 AnyHashable 完全任意的类型删除包装器Hashable符合条件的实例。

但是,假设您确实关心 Model一致性,您必须构建自己的 type-erased wrapper对于同时符合 Model 的实例和 Hashable .在 my answer here ,我演示了如何为 Equatable 构建类型橡皮擦符合类型。那里的逻辑可以很容易地扩展为 Hashable – 我们只需要存储一个额外的函数来返回 hashValue实例的。

例如:

struct AnyHashableModel : Model, Hashable {

static func ==(lhs: AnyHashableModel, rhs: AnyHashableModel) -> Bool {

// forward to both lhs's and rhs's _isEqual in order to determine equality.
// the reason that both must be called is to preserve symmetry for when a
// superclass is being compared with a subclass.
// if you know you're always working with value types, you can omit one of them.
return lhs._isEqual(rhs) || rhs._isEqual(lhs)
}

private let base: Model

private let _isEqual: (_ to: AnyHashableModel) -> Bool
private let _hashValue: () -> Int

init<T : Model>(_ base: T) where T : Hashable {

self.base = base

_isEqual = {
// attempt to cast the passed instance to the concrete type that
// AnyHashableModel was initialised with, returning the result of that
// type's == implementation, or false otherwise.
if let other = $0.base as? T {
return base == other
} else {
return false
}
}

// simply assign a closure that captures base and returns its hashValue
_hashValue = { base.hashValue }
}

var hashValue: Int { return _hashValue() }
}

然后你可以像这样使用它:

func complete(with models: [AnyHashableModel]) {
doSomethingWithHashable(models)
}

func doSomethingWithHashable<T : Hashable>(_ objects: [T]) {
//
}

let models = [AnyHashableModel(Contact()), AnyHashableModel(Address())]
complete(with: models)

这里我假设您还想将它用作 Model 的包装器的要求(假设有一些)。或者,您可以公开 base属性并删除 Model符合 AnyHashableModel本身,让调用者访问 base对于基础 Model符合实例:

struct AnyHashableModel : Hashable {
// ...
let base: Model
// ...
}

但是您会注意到,上述类型删除包装器仅适用于同时为 Hashable 的类型。和一个 Model .如果我们想讨论符合实例为 Hashable 的其他协议(protocol)怎么办? ?

一个更通用的解决方案,正如我演示的那样in this Q&A , 而是接受同时为 Hashable 的类型并符合其他一些协议(protocol)——其类型由通用占位符表示。

因为目前在 Swift 中没有办法表达一个必须符合另一个通用占位符给定协议(protocol)的通用占位符;此关系必须由调用者使用 transform 定义闭包来执行必要的向上转换。然而,由于 Swift 3.1 在扩展中接受了具体的相同类型要求,我们可以定义一个方便的初始化程序来删除 Model 的样板文件。 (对于其他协议(protocol)类型可以重复此操作)。

例如:

/// Type-erased wrapper for a type that conforms to Hashable,
/// but inherits from/conforms to a type T that doesn't necessarily require
/// Hashable conformance. In almost all cases, T should be a protocol type.
struct AnySpecificHashable<T> : Hashable {

static func ==(lhs: AnySpecificHashable, rhs: AnySpecificHashable) -> Bool {
return lhs._isEqual(rhs) || rhs._isEqual(lhs)
}

let base: T

private let _isEqual: (_ to: AnySpecificHashable) -> Bool
private let _hashValue: () -> Int

init<U : Hashable>(_ base: U, upcast: (U) -> T) {

self.base = upcast(base)

_isEqual = {
if let other = $0.base as? U {
return base == other
} else {
return false
}
}

_hashValue = { base.hashValue }
}
var hashValue: Int { return _hashValue() }
}

// extension for convenience initialiser for when T is Model.
extension AnySpecificHashable where T == Model {
init<U : Model>(_ base: U) where U : Hashable {
self.init(base, upcast: { $0 })
}
}

您现在希望将实例包装在 AnySpecificHashable<Model> 中:

func complete(with models: [AnySpecificHashable<Model>]) {
doSomethingWithHashable(models)
}

func doSomethingWithHashable<T : Hashable>(_ objects: [T]) {
//
}

let models: [AnySpecificHashable<Model>] = [
AnySpecificHashable(Contact()),
AnySpecificHashable(Address())
]

complete(with: models)

关于swift - 检查 Hashable 一致性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43263352/

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