1) 允许比较两个相同类型的可缓存对象Cacheable
protocol Cacheable: Equatable {
func identifier() -> String
}
func ==<T : Cacheable>(lhs: T, rhs: T) -> Bool {
return lhs.identifier() == rhs.identifier()
}
优点
这是最简单的解决方案。
缺点
你只能比较两个相同类型的Cacheable
对象。这意味着下面的代码将失败,为了修复它,你需要让Animal
符合Cacheable
标准:
class Animal {
}
class Dog: Animal,Cacheable {
func identifier() -> String {
return "object"
}
}
class Cat: Animal,Cacheable {
func identifier() -> String {
return "object"
}
}
let a = Dog()
let b = Cat()
a == b
2) 允许比较任何类型的可缓存对象
protocol Cacheable:Equatable {
func identifier() -> String
}
func ==<T:Cacheable>(lhs: T, rhs: T) -> Bool {
return lhs.identifier() == rhs.identifier()
}
func !=<T:Cacheable>(lhs: T, rhs: T) -> Bool {
return lhs.identifier() != rhs.identifier()
}
func ==<T:Cacheable, U:Cacheable>(lhs: T, rhs: U) -> Bool {
return lhs.identifier() == rhs.identifier()
}
func !=<T:Cacheable, U:Cacheable>(lhs: T, rhs: U) -> Bool {
return lhs.identifier() != rhs.identifier()
}
优点
消除了解决方案1中描述的限制。现在你可以轻松地比较Dog
和Cat
。
缺点
- 实现更长。实际上我不确定为什么只指定
==
函数不足以满足要求 - 这可能是编译器的一个bug。无论如何,你必须提供==
和!=
的实现。
- 在某些情况下,这种实现的好处也可能会带来问题,因为你允许比较完全不同的对象,而编译器完全没有问题。
3)不符合Equatable
规范
protocol Cacheable {
func identifier() -> String
}
func ==(lhs: Cacheable, rhs: Cacheable) -> Bool {
return lhs.identifier() == rhs.identifier()
}
func !=(lhs: Cacheable, rhs: Cacheable) -> Bool {
return lhs.identifier() != rhs.identifier()
}
优点
您可以使用Cacheable
作为类型,而无需任何泛型。这引入了全新的可能性。例如:
let c:[Cacheable] = [Dog(),RaceCar()]
c[0] == c[1]
c[0] != c[1]
使用解决方案1和2,此代码将失败,您必须在类中使用泛型。然而,使用最新的实现,
Cacheable
被视为一种类型,因此您可以声明一个类型为
[Cacheable]
的数组。
缺点:
您不再声明符合
Equatable
,因此任何接受
Equatable
参数的函数都不会接受
Cacheable
。显然,除了我们为
Cacheable
声明的
==
和
!=
之外。
如果这在您的代码中不是问题,我实际上更喜欢这个解决方案。能够将协议视为一种类型在许多情况下非常有用。
Cacheable
接口的对象,但是却得到了这样的错误信息:Binary operator '==' cannot be applied to two Cacheable operands
。 - Bobj-Clet x:Cachable = ...
将变得无效。这是Swift协议中的一个巨大问题,根据您的操作,可能很难甚至不可能解决。 - drekka