【问题标题】:Possible Bug with Swift 3 mixing Protocols, Extensions, and Class InheritenceSwift 3 混合协议、扩展和类继承的可能错误
【发布时间】:2016-10-23 06:24:09
【问题描述】:

我正在学习有关 swift、OOP 和 POP 的所有知识。当我遇到一些意想不到的行为时,我一直在将它们混合在一起以创建一个抽象基类。它最好用代码来表达,我将展示它按预期工作,然后按预期工作(至少对我来说)。代码很长,但很简单。在这里它工作正常:

protocol GodsWill           {          func conforms() }
extension GodsWill          {          func conforms() { print("Everything conforms to God's Will") } }
class TheUniverse: GodsWill {          func conforms() { print("The Universe conforms to God's Will") } }
class Life: TheUniverse     { override func conforms() { print("Life conforms to God's Will") } }
class Humans: Life          { override func conforms() { print("Though created by God, Humans think they know better") } }

let universe = TheUniverse()
let life = Life()
let humans = Humans()

universe.conforms()
life.conforms()
humans.conforms()
print("-------------------------")
let array:[GodsWill] = [universe,life,humans]
for item in array { item.conforms() }

这是输出:

The Universe conforms to God's Will
Life conforms to God's Will
Though created by God, Humans sometimes think they know better
-------------------------
The Universe conforms to God's Will
Life conforms to God's Will
Though created by God, Humans sometimes think they know better

这正是我所怀疑的。但是当第一个类没有 conforms() 的自定义实现时,我在我的应用程序中遇到了这个问题,如下所示:

protocol GodsWill           {          func conforms() }
extension GodsWill          {          func conforms() { print("Everything conforms to God's Will") } }
class TheUniverse: GodsWill {  }
class Life: TheUniverse     {          func conforms() { print("Life conforms to God's Will") } }
class Humans: Life          { override func conforms() { print("Though created by God, Humans sometimes think they know better") } }

let universe = TheUniverse()
let life = Life()
let humans = Humans()

universe.conforms()
life.conforms()
humans.conforms()
print("-------------------------")
let array:[GodsWill] = [universe,life,humans]
for item in array { item.conforms() }

请注意,TheUniverse 没有 conforms() 的自定义实现。这是输出:

Everything conforms to God's Will
Life conforms to God's Will
Though created by God, Humans sometimes think they know better
-------------------------
Everything conforms to God's Will
Everything conforms to God's Will
Everything conforms to God's Will

前三行 print() 正是我所期望和想要的,但后三行确实让我感到困惑。由于 conforms() 是协议要求,因此它们应该与前三行相同。但是我得到的行为好像 conforms() 是在协议扩展中实现的,但没有列为协议要求。 The Swift Programming Language 参考手册中没有关于此的内容。 this WWDC video 正好在 30:40 证明了我的观点。

那么,是我做错了什么,误解了功能,还是发现了 swift 3 中的错误?

【问题讨论】:

    标签: swift inheritance protocols swift3 protocol-extension


    【解决方案1】:

    经过进一步调查,我认为这与 WWDC 视频没有太大关系。

    Universe 没有定义 conforms 方法,因此在 Universe 上调用 conforms 将打印“Everything...”。

    Life 定义了一个conforms 方法。但是,由于它继承自 Universe,由于扩展,它已经实现了 conforms,因此协议并不真正需要 conforms 方法。因此,协议类型忽略了Life 类中的conforms 方法。换句话说,Life 中的conforms 方法是遮蔽协议扩展中的conforms 方法,我们可以在以下输出中看到:

    let a: TheUniverse = Life()
    a.conforms()
    Life().conforms()
    // output:
    // Everything conforms to God's Will
    // Life conforms to God's Will
    

    人类还有另一种conforms 方法。这一次,它是用override 定义的。但是,这个override 不会覆盖协议扩展中的conforms 方法。相反,它覆盖了Life 中的conforms 方法,这是Humans 的直接超类。这可以通过以下代码的输出来证明:

    let a: Life = Humans()
    a.conforms()
    // output:
    // Though created by God, Humans sometimes think they know better
    

    所以毕竟协议扩展中的方法没有被覆盖。所以当你创建一些对象并将其放入[GodsWill]时,阴影没有效果,因此调用了协议扩展方法。

    【讨论】:

    • 那么解决这个问题的方法是什么?我有多个符合 GodsWill 的类,我希望所有这些类都具有相同的默认实现。我想如果我可以在基类中包含一个简单地调用扩展实现的存根,它将完成电路并正常运行。我试过这个:TheUniverse 中的func conforms() { super.conforms() },但这是一个编译时错误。我在 TheUniverse 中尝试过func conforms() { (self as GodsWill).conforms() },但这是一个无限循环。我如何在 TheUniverse 的 GodsWill 上调用 conforms()?
    • @mogelbuster 哦,是的,我忘了提这个!只是不要从TheUniverse 继承任何东西。为什么Life不能直接符合GodsWill
    • Life需要继承TheUniverseLife需要符合GodsWill。这会起作用,除了TheUniverse 还需要符合GodsWill。所以Life不能直接符合GodsWill。我可以简单地将conforms() 的默认实现放在TheUniverse 中,但可以说现实比我们想象的要大,而且我还有两个基类EvilParallelUniverseHeavenlyParallelUniverse,它们都必须符合GodsWill。它们都使用conforms() 的默认实现,但它们的无数子类必须自定义该实现。
    • 我想我可以使 GodsWill 成为 Universe 类的基类,而不是协议,但这会减少 GodsWill 的代码重用和可扩展性,这正是快速协议扩展。或者,我可以创建一个新的基类TheMultiverse,它是所有宇宙的超类,删除GodsWill 的协议扩展(但保留协议本身)并将conforms() 的默认实现移动到TheMultiverse 中。但是如果我必须做所有这些,那么协议扩展的目的是什么?这似乎是一个快速的设计缺陷。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多