使快速协议符合Hashable

时间:2020-10-21 17:14:10

标签: ios swift protocols swift-protocols hashable

我正四处逛逛,试图使Hashable与多个struct一起使用,而这些protocol符合同一SomeLocation

我有一个这样声明的协议protocol SomeLocation { var name:String { get } var coordinates:Coordinate { get } }

struct ShopLocation: SomeLocation, Decodable {
    var name: String
    var coordinates: Coordinate

    init(from decoder: Decoder) throws {
        ...
    }
}

struct CarLocation: SomeLocation, Decodable {
    var name: String
    var coordinates: Coordinate

    init(from decoder: Decoder) throws {
        ...
    }
}

然后,我创建多个包含类似数据的对象,如下所示:

let locations: [SomeLocation]

我以后可以通过声明以下内容在同一数组中使用它们:

MKAnnotation

问题是,我创建了一个Hashable子类,并且需要在SomeLocation对象上使用自定义final class LocationAnnotation:NSObject, MKAnnotation { let location:SomeLocation init(location:SomeLocation) { self.location = location super.init() } } override var hash: Int { return location.hashValue } override func isEqual(_ object: Any?) -> Bool { if let annot = object as? LocationAnnotation { let isEqual = (annot.location == location) return isEqual } return false }

Hashable

这给了我两个错误:

“ SomeLocation”类型的值没有成员“ hashValue”二进制运算符

'=='不能应用于两个'SomeLocation'操作数

因此,我将SomeLocation协议添加到了protocol SomeLocation: Hashable { ... } 协议中:

let location:SomeLocation

这消除了hashValue不可用的第一个错误,但是现在我在声明Hashable

时收到错误

协议“ SomeLocation”只能用作通用约束,因为它具有“自我”或相关联的类型要求

因此看来我不能在协议中添加Hashable

我可以将SomeLocation直接添加到实现SomeLocation协议的每个结构中,但是,这意味着我需要使用这样的代码,并在每次可能使另一个符合该规范的对象时不断对其进行更新。 override var hash: Int { if let location = location as? ShopLocation { return location.hashValue } return self.hashValue } 协议。

SomeLocationRepresentable

我尝试了另一种方法,即制作一个struct SomeLocationRepresentable { private let wrapped: SomeLocation init<T:SomeLocation>(with:T) { wrapped = with } } extension SomeLocationRepresentable: SomeLocation, Hashable { var name: String { wrapped.name } var coordinates: Coordinate { wrapped.coordinates } func hash(into hasher: inout Hasher) { hasher.combine(name) hasher.combine(coordinates) } static func == (lhs: Self, rhs: Self) -> Bool { return lhs.name == rhs.name && lhs.coordinates == rhs.coordinates } } 结构:

LocationAnnotation

但是,当我尝试在let location: SomeLocationRepresentable init(location:SomeLocation) { self.location = SomeLocationRepresentable(with: location) super.init() } 类中使用它时,

Hashable

我遇到错误

协议类型“ SomeLocation”的值不符合“ SomeLocation”;只有struct / enum / class类型可以符合协议

是否有可能实现我想做的事情?使用所有都符合协议的对象,并使用自定义keytool -exportcert -alias foodtimeph -keystore /Users/eliedanhash/Downloads/ph/foodtimeph.keystore.jks | openssl sha1 -binary | openssl base64 来比较一个对象?

1 个答案:

答案 0 :(得分:1)

Hashable导出协议并使用类型橡皮擦可能会在这里有所帮助:

protocol SomeLocation: Hashable {
    var name: String { get }
    var coordinates: Coordinate { get }
}

struct AnyLocation: SomeLocation {
    let name: String
    let coordinates: Coordinate
    
    init<L: SomeLocation>(_ location: L) {
        name = location.name
        coordinates = location.coordinates
    }
}

然后,您可以简单地在结构上声明协议一致性,并且如果Coordinate已经是Hashable,则无需编写任何额外的哈希码代码,因为编译器可以自动合成为您服务(只要所有类型的属性均为Hashable

struct ShopLocation: SomeLocation, Decodable {
    var name: String
    var coordinates: Coordinate
}

struct CarLocation: SomeLocation, Decodable {
    var name: String
    var coordinates: Coordinate
}

如果Coordinate也是Codable,那么您也可以省略为编码/解码操作编写的任何代码,编译将综合所需的方法(前提是所有其他属性已经为{{1} }。

然后您可以通过转发初始化器约束来在注释类中使用橡皮擦:

Codable