我正在尝试让Hashable
与符合相同protocol
的多个struct
一起使用,但却走了弯路。
我有一个声明为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子类并需要在SomeLocation对象上使用自定义的Hashable。
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
}
这给了我两个错误:
类型 'SomeLocation' 的值没有成员 'hashValue' 二进制运算符
'==' 不能应用于两个 'SomeLocation' 操作数
因此,我将 Hashable
协议添加到我的 SomeLocation
协议中:
protocol SomeLocation: Hashable {
...
}
这样就解决了hashValue不可用的第一个错误,但是现在我遇到了另一个错误,在声明
let location:SomeLocation
时出现以下错误提示:
看起来我似乎不能将Protocol 'SomeLocation' can only be used as a generic constraint because it has Self or associated type requirements
Hashable
添加到该协议中。我可以直接将
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()
}
我遇到了一个错误
协议类型“SomeLocation”的值无法符合“SomeLocation”;只有结构体/枚举/类类型才能符合协议
我正在尝试做的事情是否可行?使用所有符合某个协议的对象,并使用自定义的Hashable
将其相互比较?
[SomeLocation]
时)将协议用作存在形式(即代替对象),同时还尝试符合Hashable,它具有Self约束,这会防止它在Swift中被用作存在形式。类型抹消(就像你使用SomeLocationRepresentable
一样 - 在Swift中的惯例是将其命名为AnyLocation
)是正确的方法,因此您将拥有var locations:[AnyLocation] = [AnyLocation(CarLocation())]
。 - New DevSomeLocation
初始化SomeLocationRepresentable
,而它期望的是符合SomeLocation
的类型。协议不符合协议,包括它们自己。当您有Self
约束(Hashable
就是这种情况)时,您基本上不能拥有一个是SomeLocation
的东西。 - New DevSomeLocation
的值转换为SomeLocationRepresentable
:/ - Darren