在WWDC 2015上提到了以下代码:
protocol Drawable {
func isEqualTo(other: Drawable) -> Bool
func draw()
}
extension Drawable where Self : Equatable {
func isEqualTo(other: Drawable) -> Bool {
if let o = other as? Self { return self == o }
return false
}
}
我对整个协议扩展的事情有点困惑。为什么他们在isEqualTo(other: Drawable) -> Bool
协议中有Drawable
,然后只在self
等于时延伸?为什么isEqualTo
必须成为所有Drawable对象的必需方法?从我的角度来看,如果一个新的类/结构没有实现Equatable
,那么这些对象就无法在逻辑上检查其是否相等,所以它们不能<\ n < / em>实现一个等同的方法。我认为将它作为可选实现更有意义。我逻辑中的错误在哪里?
答案 0 :(得分:3)
正在解决的问题是泛型的限制。
让我们说我们有一个Bird结构和Insect结构。通用equable允许我们定义b1
,其中实际的对象类型是相同的类型。所以我们可以让Bird采用Equatable,这样如果我们将b2
和i1
都输入Bird,我们可以决定它们是否相等。我们可以让Insect采用Equatable,这样如果我们将i2
和==
都输入为Insect,我们就可以决定它们是否相等。
但现在假设Bird和Insect都采用Flier协议。你不能让Flier采用Equatable,因为泛型的工作方式有限制。因此,如果将两个对象键入为Flier,则无法实现它们的兼容性。
该视频演示了协议扩展解决了这个问题。通过Flier上的协议扩展,您可以定义一个不同的方法,该方法比较两个Fliers并确定它们是否相等 - 即,首先确定它们是否属于同一个类然后应用{{1} }。因此,您可以理解Flier(协议)的等同性。
答案 1 :(得分:1)
我只能猜测为什么isEqualTo:
是drawable协议的必需方法。也许是这样,无论是什么吸引这些东西,都不会浪费时间画两次相同的东西?
然而,我可以评论其余部分。
Equatable
是一个Swift协议(在Objective-C中不可用),它要求为该类型定义==
运算符。
在Objective-C中,没有运算符重载。此外,在Objective-C中,使用==
比较对象只是比较它们的指针。如果对象是同一个对象(相同的内存位置),==
将返回true。如果我们想要查看对象是否是不同的对象但仍然被认为是相等的,我们必须使用isEqualTo:
。这是由NSObject
定义的方法,默认实现只返回==
比较的结果。但是类往往会覆盖它。
在Swift中,==
有不同的行为。在Swift中,==
返回的行为与我们期望isEqualTo:
方法在Objective-C中的行为方式类似。那是因为Swift有===
运算符用于比较引用。如果这些对象相同(相同的内存位置),则===
返回true,但==
是一个自定义实现的方法,用于确定对象是否被认为是相等的,即使它们在不同的记忆位置。
所以我猜测Drawable
协议在声明isEqualTo:
作为其必需方法之一时,会考虑Objective-C类。
我们也可以这样编写Drawable
协议:
protocol Drawable: Equatable {
func draw()
}
从严格的Swift角度来看,这是一个大致相当的协议定义。但这意味着使用Drawable
对象的任何人都希望将它们与Swift中的==
进行比较,而不是isEqualTo:
。而且,这意味着如果我们想在协议中使用任何Objective-C定义的对象,现在我们必须为每个对象实现一个自定义==
函数,这很可能是这样的:
func == (left ObjCClass, right ObjCClass) -> Bool {
return left.isEqualTo(right)
}
但我们必须为我们想要定义为Drawable
的每个 Objective-C类执行此操作。
另一种方法是使用isEqualTo:
(一种非常常见的Objective-C方法)定义我们提供的协议。
现在,为了使我们的所有Swift类型都符合Drawable
,我们所要做的就是实现draw()
方法并符合Equatable
。只要我们符合Equatable
,扩展程序就会将isEqualTo:
方法作为简单的return left == right
有效地添加到我们的Swift类型中(并且==
方法的存在就是什么Equatable
协议保证)。