检查 Hashable 一致性

2023-12-06

我有一些结构符合的基本协议(模型)。它们也符合 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] 传递给需要 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,它承诺nothing about Hashable一致性。正如您所指出的,告诉编译器这一点的问题(即派生Model from Hashable)那么你是否就失去了用符合的异质类型进行交谈的能力Model.

如果你根本不关心Model首先要保持一致性,您可以使用标准库的AnyHashable类型擦除包装完全任意 Hashable符合实例。

但是,假设您确实关心Model一致性,你必须建立自己的类型擦除包装对于同时符合两者的实例Model and Hashable. In 我的回答在这里,我演示了如何构建类型橡皮擦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 and a Model。如果我们想讨论符合实例的其他协议怎么办Hashable?

正如我所演示的,一个更通用的解决方案在本次问答中,是改为接受两者兼而有之的类型Hashable并符合其他一些协议——其类型由通用占位符表示。

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

例如:

/// 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)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

检查 Hashable 一致性 的相关文章

  • 设置惰性静态变量首先初始化然后分配?

    我意识到static变量是隐式的lazy 这真的很棒 执行以下操作在第一次调用之前不会创建实例 static var test Test 但是 将一个新实例分配给static变量初始化原始实例 然后分配新实例 这对我来说很麻烦 SomeTy
  • Swift 中的 NSManagedObject 描述

    发生了一些奇怪的事情NSManagedObject description 它只打印一个空行 import Foundation import CoreData objc MyEntity class MyEntity NSManagedO
  • 通用列表 FindAll() 与 foreach

    我正在浏览通用列表以查找基于特定参数的项目 一般来说 最好和最快的实施是什么 1 循环遍历列表中的每个项目并将每个匹配项保存到新列表中并返回 foreach string s in list if s match newList Add s
  • Swift 错误中的 UIColor 扩展

    我有这个扩展 extension UIColor func rgba r Int g Int b Int a Float gt UIColor return UIColor red r 255 green g 255 blue b 255
  • 检查 u 键是否被按下 Swift Cocoa [重复]

    这个问题在这里已经有答案了 我正在尝试检测是否U键是否被按下 如果是的话应该print BUT BUT 但我不确定如何检查不同的按键 因为按键的文档非常糟糕 我找到了带有键码的答案 但它们仅适用于 QWERTY 键盘 视图控制器 swift
  • Swift - 带有两行文本的 UIButton

    我想知道是否可以创建一个包含两行文本的 UIButton 我需要每一行都有不同的字体大小 第一行为 17 点 第二行为 11 点 我尝试过将两个标签放在 UIButton 内 但我无法让它们留在按钮的范围内 我试图在 ui 构建器中完成所有
  • 如何一次运行多个后台线程任务?

    我正在尝试循环遍历包含 2016 年 10 月日期的 String 对象数组 这意味着 31 个 String 对象 2016 年 10 月 1 日 2016 年 10 月 31 日 对于每个对象 我想从数据库检索一些数据并附加返回值 也是
  • 为什么UICollectionViewCell的outlet为nil?

    我在 Interface Builder 中创建了一个自定义 UICollectionViewCell 将其上的视图绑定到类 然后当我想使用字符串并将其设置为字符串上的标签时 该标签具有 nil 值 override func viewDi
  • 使 Picker 与其他 BinaryInteger 类型兼容

    Picker仅当与以下一起使用时才能正常工作Int 当使用任何其他类型的BinaryInteger它根本不更新选择 为了解决这个问题 我想做一个CompatilibityPicker但我必须承认我的理解Binding实际上工作给我带来了很多
  • 什么是 Swift 枚举字节表示?

    我有以下枚举 enum Enum UInt8 case A 0x00 case B 0x01 case C 0x10 我使用以下代码将其转换为NSData var value Enum C let data NSData bytes val
  • 如何在 SWIFT 中实现 Objective-C 回调处理程序?

    目标c代码如下所示 void signInAccountWithUserName NSString userName password NSString password completion void BOOL success compl
  • 将领域列表转换为领域结果

    只是想知道如何将列表转换为结果 因为我正在对区域和区域进行过滤 当用户选择区域时 区域应该仅显示该区域中的那些区域 当我将我的区域分配给定义为的变量时var areas Results area 我得到了编译错误 无法将 列表 类型的值分配
  • 如何在 Swift MacOS 应用程序中实现 AppleScript 支持

    我正在做一个SwiftMacOS 应用程序通过串行端口与外部设备交互 我可以通过应用程序控制设备 但我希望能够使用 AppleScript 在其他应用程序中控制它 我需要的只是one简单的方法就像tell application App t
  • 如何为除用户位置之外的所有点设置自定义注释?

    授权检查后 为了获取用户位置 我调用此 CLLocation 委托函数 func locationManager manager CLLocationManager didUpdateLocations locations CLLocati
  • iOS、Swift 3 - 当我从详细视图返回后单击“取消”时,UISearchBar 消失

    我在containerView中有一个tableView 以编程方式向其添加一个搜索栏 一切工作正常 除了这种情况 当我点击一个单元格时 当 tableView 由 searchBar 过滤时 然后我从明细视图返回 通过推送转场呈现 然后我
  • EXC_BAD_ACCESS 在使用 Swift 字典评估 NSExpression 后更新它时

    我正在使用字典来评估表达式 当表达式有变量并且字典实际上由 NSExpression 使用时 会发生一些事情 并且在尝试更新字典时我得到 EXC BAD ACCESS 这仅在 iPhone6 中调试时发生 而不是在模拟器而不是 iPhone
  • 显示键盘时检测 UITextView 中属性文本的点击

    这是一个补充问题我之前的一个回答 https stackoverflow com a 32262426 3681880对这个问题检测 iOS 中 UITextView 中属性文本的点击 https stackoverflow com que
  • .NET 中可以使用通用 BitConverter.GetBytes 吗?

    是否可以创建类似的方法BitConverter GetBytes 也接受作为输入范围类型的Object 不使用编组处理here https stackoverflow com questions 1455581 generic bitcon
  • 如何单击“取消”按钮退出搜索?

    我有一个带有取消按钮的搜索栏 但是当我单击 取消 按钮时 它不会关闭搜索栏 如何使单击 取消 时将搜索栏返回到第一个状态 如果您有任何疑问 请询问我 您需要实现 UISearchBarDelegate class ViewControlle
  • iPadOS:通过 NEHotspotConfiguration 连接的网络在一段时间后断开连接

    我的应用程序使用NEHotspotConfigurationManager使用 Wi Fi 将自身连接到特定设备 该设备充当 WPA2 接入点 在较旧的 iOS 版本 iOS 12 及更低版本 中 一切正常 但在 iPadOS iOS 13

随机推荐

  • 在 python、numpy 中创建一个全零的 4d 矩阵

    我正在尝试使用以下代码在 python 中创建一个 4 维矩阵 import numpy as np rho np zeros 2 2 2 2 但我收到以下错误 rho np zeros 2 2 2 2 TypeError function
  • 如何从一个输入标签添加/上传/选择多个文件?

    我来这里是为了知道如何从一个多个输入标签添加 上传 选择多个文件 但再次选择后所有先前的选择都被删除或覆盖 我想要的是 选择多个文件 将进行预览 确定完成 用户可以从预览中删除选择 将更多文件 图像添加到当前选择 您可以隐藏输入 type
  • ORDER BY 和WITH(行锁、UPDLOCK、READPAST)

    我需要使用一些 SQL 表来设置队列系统 如所描述的那样here 也就是说 因为我需要按不同的标准过滤队列项目 所以在我正在使用的存储过程中 BEGIN TRANSACTION CREATE TABLE Temp ID INT SOMEFI
  • PhoneGap - 存储图像,然后获取其 base64 编码数据

    我正在使用 PhoneGap Camera API 拍照并使用destinationType FILE URI 这部分正在发挥作用 随后我可以采用提供的路径并将其设置为 HTML 图像的 src 然后图像就会出现 稍后在代码中 我想抓取图像
  • 使用 GCloud KMS 生成加密密钥以访问私有存储库作为依赖项时出现错误

    我正在尝试使用此将加密的 ssh 密钥添加到 google KMS文档用于访问私有存储库作为 Google App Engine Node JS 项目 的依赖项 我已成功生成 Cloud KMS KeyRing 和 CryptoKey 但在
  • 如何处理CEdit在父窗体中的鼠标点击?

    我是 MFC 的新手 来自 C 和 Java 并且正在解决问题 考虑一个包含三个文本框的对话框 我已将 CEdit 子类化为 CMyEdit 并且三个文本框连接到对话框类中的 CMyEdit 变量 我想让对话框类 知道 何时用鼠标左键单击了
  • 转换以删除重复项并复制其余部分

    我希望输出 xml 根据属性 f 针对元素 c 进行分组 这是我的输入 xml 和 xslt 我希望该组仅出现一次 其他节点应按原样复制到输出 我尝试过的 xslt 复制了整个输入 xml 因此 如果有两个或多个具有 c 元素且 f 属性值
  • 缩放级别的任何更改都会导致我的所有标记重新出现在我的 Google 地图上

    缩放级别的任何更改都会导致自上次页面加载以来随时出现在地图上的所有标记出现在地图上 无论缩放级别更改是由于我的代码中的 setZoom 调用还是因为我操作缩放滑块 情况都是如此 我有一个地图控件小部件 其中带有按钮来添加对应于不同类别的标记
  • 通过简单的训练进行手写识别

    我一直在阅读 并尝试 之前答案中建议的 OCR 程序 但我仍然没有对我的问题给出明确的答案 我需要识别手写英文文本 文本将是多行 但每行只有一两个字长 该文本有时来自不同的人 我可以要求那个人提供一个培训文件 例如 包含字母和 0 9 数字
  • iOS:如何测量经过的时间,独立于时钟和时区的变化?

    为了测量我的应用程序运行时的持续时间 以及我的应用程序在后台空闲时经过的时间 我需要一个参考时钟 该参考时钟不会因用户更改其日历时钟的时间 日期而改变 我不能依赖 NSDate 因为当我的应用程序在后台运行时 用户可以更改它 不 拦截与此类
  • NSDate 延迟日期更改

    这可能是一个简单的解决方案 但有谁知道如何将 NSDate 更改延迟到午夜之后 任何见解都会非常有帮助 谢谢 Edit 我目前正在通过这种方式获取日期并显示基于当天的位置数据 但是 就像 NSDate 在逻辑上应该起作用一样 它会在午夜切换
  • 固定表单的位置

    我正在启动一个 winform 应用程序 NET 3 5 C 其中应用程序的主窗体从特定的指定位置启动 我为此在构造函数中调用以下代码 private void SetFormPosition this StartPosition Form
  • PHP Carbon,获取日期范围内的所有日期?

    如何在 PHP 中获取两个日期之间的所有日期 更喜欢使用 Carbon 来处理日期 from Carbon now to Carbon createFromDate 2017 5 21 我想获得这两个日期之间的所有日期 但是如何呢 只能使用
  • mousemoved 事件中的 Javafx 滑块值

    我正在制作一个媒体播放器 并尝试在将鼠标悬停在滑块上时获取光标位置处的播放滑块值 为了尝试做到这一点 我使用了以下内容 timeSlider addEventFilter MouseEvent MOUSE MOVED event gt Sy
  • 我可以使用 jQuery 淡入淡出颜色吗?

    我有 javascript 可以使用如下函数更改一些 HTML if correct true ft2 html Correct ft2 css color Green ft2 css border color Green else ft2
  • PHP脚本输出的AJAX持续响应

    我的 PHP 脚本的 AJAX 响应有问题 我创建了 Status div 我想在其中输出 PHP 脚本的响应 它工作得很好 但是只有当整个脚本完成时才会显示响应 我想 实时 输出每个回声 这是我的文件 form php div class
  • 在PHP中,如何检测是从CLI模式执行还是通过浏览器执行? [复制]

    这个问题在这里已经有答案了 我有一个通用脚本 我将其包含在我的 PHPcron 文件和通过浏览器访问的文件中 代码的某些部分 我只需要非 cron 文件 我如何检测执行是从 CLI 还是通过浏览器 我知道可以通过使用 cron 文件传递 一
  • Git LFS git lfs migrate import 包括 .gitattribute 中指定的所有文件类型?

    我安装了 git lfs 并创建了一个 gitattribute 文件 其中包含许多要跟踪的文件类型 我现在想对 gitattribute 中指定的所有文件类型运行 git lfs migrate 命令 我怎样才能做到这一点 我发现的所有源
  • 页面上的某些控件对于 MS UI Automation 不可见

    我们有一个带有 StartPage xaml 的应用程序 其中 TabControl 的控件模板定义了一些网格和堆栈面板 该模板中的 xaml 中间有一个 itemPresenter 其下方有一个堆栈面板 虽然它对用户来说工作得很好 但 M
  • 检查 Hashable 一致性

    我有一些结构符合的基本协议 模型 它们也符合 Hashable protocol Model struct Contact Model Hashable var hashValue Int return static func lhs Co