我正四处逛逛,试图使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
来比较一个对象?
答案 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