1

我刚刚更新到 Xcode 11.4。我收到以下错误:

Overridden method 'equals' has generic signature <T where T : Gradient> which is incompatible with base method's generic signature <T where T : Fill>; expected generic signature to be <T where T : Fill>

在此处输入图像描述

class Fill: Equatable {
    func equals<T>(other: T) -> Bool where T: Fill { }
}

func ==<T> (lhs: T, rhs: T) -> Bool where T: Fill {
    return lhs.equals(other: rhs)
}

class Gradient: Fill {
    override func equals<T>(other: T) -> Bool where T: Gradient { }
}

这是如何改变的?

4

3 回答 3

1

请查看此线程 https://forums.swift.org/t/method-override-with-a-generic-signature-with-requirements-not-imposed-by-the-base-method/33593

此编译错误可防止您将来崩溃。

于 2020-03-25T22:33:19.717 回答
0

就我而言,我只是通过以下方式修复此错误:-

override func equals<T>(other: T) -> Bool where T: Fill {
    guard let other = other as? Gradient else { 
        return false 
    }
    ...
}

但是 Macaw 也有一些类似的错误,所以只需将 Gradient 替换为您的错误问题即可修复。

于 2020-06-06T07:48:54.070 回答
0

您不能像这样更改约束的原因是因为这样做会违反 Liskov 替换原则。编译器从未检查过覆盖函数的通用签名,这导致了各种运行时崩溃,所以我在 Swift 5.2 编译器中实现了这个错误。

让我们看一下您自己的示例以了解问题所在。可以编写以下代码:

let fill1: Fill = Fill()
let fill2: Fill = Gradient()
let isEqual = fill2.equals(other: fill1)

这是不正确的,因为Gradient.equals(other:)需要other继承自Gradient. 但是,因为fill2有一个静态类型Fill,我能够绕过该约束并传递一个类型的值Fill

如果Gradient.equals(other:)尝试访问仅存在于 的实例上other的属性或函数,您的代码只会在运行时崩溃,因为该属性或函数在 上不可用:GradientFill

class Fill: Equatable {
  func equals<T>(other: T) -> Bool where T: Fill { ... }
}

class Gradient: Fill {
  private(set) var id: String = UUID().uuidString
  override func equals<T>(other: T) -> Bool where T: Gradient {
    return id == other.id // crash if `other` is value of type `Fill`
  }
}

因此,编译器现在禁止您在覆盖函数时添加不兼容的约束。

现在,基本上有两种方法可以解决问题 - 更改代码并避免在覆盖函数中添加不兼容的约束,或者在覆盖函数中执行运行时检查,as?或者type(of:)检查传递的值是否确实满足新约束,然后尝试使用它:

override func equals<T>(other: T) -> Bool where T: Gradient {
  if type(of: other) == Fill.self { return false }
  return id == other.id // okay
}
于 2020-07-02T20:25:05.037 回答