3

我试图做的事情:

protocol HasElement {
    associatedtype ItemType
    func getElement() -> ItemType
    func setElement(element: ItemType)
}

class Element {}
class BarElement: Element {}

class Foo: NSObject, HasElement {
    typealias ItemType = Element
    func getElement() -> Element { ... }
    func setElement(element: Element) { ... }
}

class Bar: Foo {
    typealias ItemType = BarElement
    override func getElement() -> BarElement { ... } // This works.
    override func setElement(element: BarElement) { ... } // This fails.
}

错误是:

方法不会覆盖其超类中的任何方法

如果我尝试改用 ItemType:

override func setElement(element: ItemType) { ... }  // Still fails.

错误是:

在这种情况下,“ItemType”对于类型查找不明确

有没有办法使这项工作?

4

3 回答 3

2

这里的问题不是关联类型,而是方法输入是逆变的。因此,您不能用期望子类实例输入的方法覆盖期望给定超类实例输入的方法。

实际上,您可以简单地将代码归结为:

class Element {}
class BarElement : Element {}

class Foo {
    func setElement(element: Element) { }
}

class Bar : Foo {
    // error: Method does not override any method from its superclass
    override func setElement(element: BarElement) { }
}

您根本无法用方法覆盖(Element) -> Void方法(BarElement) -> Void。如果您考虑创建Bar实例并将其向上转换为Foo. 您现在可以将实例传递给需要Element实例的方法BarElement,这是非法的。

它适用于您的getElement方法的原因是方法输出是covariant() -> Element因此,用方法覆盖() -> BarElement方法是完全合法的,因为即使您将Bar实例向上转换为FooBarElement从返回的实例getElement也可以自由向上转换为Element

至于解决方案,它取决于您的确切用例。很可能您正在尝试做的事情根本不需要继承,相反,您可以单独遵循和Foo遵循。BarHasElement

于 2016-09-28T10:04:56.740 回答
2

这是一种做你想做的事情的方法:

protocol HasElement {
  associatedtype ItemType
  func getElement() -> ItemType
  func setElement(element: ItemType)
}

class Element {}
class BarElement: Element {}

class Foo: HasElement {
  // no need for typealias, the associated type is inferred
  func getElement() -> Element { return Element() }
  func setElement(element: Element) { }
}

class Bar: Foo {
  // no need for typealias, the associated type is inferred
  override func getElement() -> BarElement { return BarElement() }

  // hide the parent class method
  @available(*, unavailable, message: "Use setElement(element: BarElement)")
  override func setElement(element: Element) { }

  // comply with protocol in this class
  func setElement(element: BarElement) { }
}

// can't do this now:
let myElement = Element()
let myBar = Bar()
myBar.setElement(element: myElement) // Error: 'setElement(element: BarElement)' is unavailable: Use setElement(element: BarElement)
于 2016-09-28T01:17:22.393 回答
1

这有效:

override func getElement() -> BarElement { ... }

usingoverride关键字是当函数签名不改变时(BarElement仍然Element)。您从具有相同函数名称、相同参数名称和相同返回值类型的超类中复制和粘贴函数。

override func setElement(element: BarElement) { ... }

失败,因为当您更改参数类型(具有相同的参数名称)时。这种情况是重载而不是覆盖。

于 2018-05-30T11:16:50.677 回答