【问题标题】:class AnyComparable inherits from class AnyEquatable类 AnyComparable 继承自类 AnyEquatable
【发布时间】:2021-08-22 04:40:10
【问题描述】:
public class AnyEquatable: Equatable {
    public let value: Any
    private let equals: (Any) -> Bool

    public init<E: Equatable>(_ value: E) {
        self.value = value
        self.equals = { $0 as? E == value }
    }

    public static func == (lhs: AnyEquatable, rhs: AnyEquatable) -> Bool {
        lhs.equals(rhs.value) || rhs.equals(lhs.value)
    }
}

public class AnyComparable: AnyEquatable, Comparable {
    private let compares: (Any) -> Bool

    public init<C: Comparable>(_ value: C) {
        super.init(value)
        self.compares = { ($0 as? C).map { $0 < value } ?? false }
    }

    public static func < (lhs: AnyComparable, rhs: AnyComparable) -> Bool {
        lhs.compares(rhs.value) || rhs.compares(lhs.value)
    }
}

我有一个错误:

重写方法“init”具有通用签名 C,其中 C: Comparable 与基本方法的通用签名不兼容 E 其中 E:等式;预期的通用签名为 C 其中 C: 平等的

为什么编译器认为我覆盖了初始化程序?我没有使用“覆盖”这个词。我不能在这里覆盖,因为方法“init”具有不同的签名(编译器告诉自己)。它不是压倒一切的。我希望子类使用自己的初始化程序,而且我(显然)不想继承超类初始化程序。
那么,我该如何实现呢?有什么比继承自平等的东西更自然的了!为什么我不能这样做?

【问题讨论】:

  • @LeoDabus 我从这里得到的主要思想:stackoverflow.com/a/46288607/2167345
  • 尽量不要继承 AnyEquatable。 class AnyComparable: Comparable &amp; Equatable {
  • 顺便说一句,您希望如何对不同类型进行排序?如果它们相等,为什么需要检查不同的类型?
  • 派生类中的init实际上是一个override。签名是“不兼容的”,因为如果允许它会违反“Liskov 替换原则”。

标签: swift inheritance initialization


【解决方案1】:

请注意,子类中的初始化器确实会覆盖超类中的初始化器。如果您按照编译器的要求修复C 的约束,编译器会告诉您的下一件事是您缺少override 关键字。

这种行为是相当一致的,因此在确定一种方法是否覆盖另一种方法时,似乎故意设计为不考虑通用约束。这是另一个例子:

class A {
    func f<T>(t: T) {}
}

class B: A {
    func f<C: Equatable>(t: C) {} // error
}

无论如何,解决此问题的一种方法是更改​​参数标签:

public init<C: Comparable>(comparable value: C) {
    self.compares = { ($0 as? C).map { $0 < value } ?? false }
    super.init(value)
}

这样做的缺点是客户端代码不太简洁。你必须每次都做AnyComparable(comparable: something),这很长。一种解决方案是将AnyEquatableAnyComparable 放在同一个文件中,使两个初始化器fileprivate。然后,您可以提供创建这些类的工厂函数(在同一个文件中)。例如:

public extension Equatable {
    func toAnyEquatable() -> AnyEquatable {
        .init(equatable: self)
    }
}

public extension Comparable {
    func toAnyComparable() -> AnyComparable {
        .init(comparable: self)
    }
}

另请注意,您对&lt; 的实现没有多大意义。应该是:

public static func < (lhs: AnyComparable, rhs: AnyComparable) -> Bool {
    lhs.compares(rhs.value) || (rhs != lhs && !rhs.compares(lhs.value))
}

compares 应该表示“小于”,

self.compares = { ($0 as? C).map { value < $0 } ?? false }

说“lhs lhs”。

但即便如此,在某些情况下,将此类与完全不相关的类型一起使用仍然没有多大意义,仅供参考:

let a = AnyComparable(comparable: "foo")
let b = AnyComparable(comparable: 1)
print(a < b) // true
print(a > b) // true
print(a <= b) // false
print(a >= b) // false
print(a == b) // false

所以请小心!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-27
    • 2011-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-07
    • 1970-01-01
    相关资源
    最近更新 更多