簡體   English   中英

如何在Swift中比較兩個協議數組的相等性?

[英]How to compare two arrays of protocols for equality in Swift?

我遇到了一種我確定並不常見的情況。 我有兩個符合協議的對象數組,我想檢查它們是否相等。

我真正想做的是:

protocol Pattern: Equatable
{
    func isEqualTo(other: Pattern) -> Bool
}

func ==(rhs:Pattern, lhs:Pattern) -> Bool
{
    return rhs.isEqualTo(lhs)
}

extension Equatable where Self : Pattern
{
    func isEqualTo(other: Pattern) -> Bool
    {
        guard let o = other as? Self else { return false }
        return self == o
    }
}

但是,這會導致編譯錯誤:

Error:(10, 30) protocol 'Pattern' can only be used as a generic constraint because it has Self or associated type requirements

基於這篇文章,我意識到我需要在協議上丟失Equatable繼承並將其推送到具體的“Pattern”聲明。 雖然我真的不明白為什么。 如果我通過重載來定義基於協議的兩個對象是如何相等的==就我所見,確實沒有問題。 我甚至不需要知道實際類型或它們是類還是結構。

無論如何,這一切都很好,我現在可以比較concretePattern.isEqualTo(otherConcretePattern)但問題仍然是我不能再比較這些對象的數組,就像我可以比較具體類型的數組,因為數組相等依賴於重載==運算符。

到目前為止,我設法做的最好的是通過擴展將一個isEqualTo方法放到CollectionType上。 這至少允許我比較數組。 但坦率地說,這段代碼很臭。

extension CollectionType where Generator.Element == Pattern
{
    func isEqualTo(patterns:[Pattern]) -> Bool {
        return self.count as? Int == patterns.count && !zip(self, patterns).contains { !$0.isEqualTo($1) }
    }
}

真的沒有別的辦法嗎? 請告訴我,我錯過了一些明顯的東西。

我有兩個符合協議的對象數組,我想檢查它們是否相等。

所以你想說兩個數組是相等的,如果它們中的所有元素都相等並且元素都符合模式。

如果a,b,c和d都是符合Pattern的東西,那么你想要的

a == c 
a != b
a != d
b != d

let array1: [Pattern] = [a, b, c]
let array2: [Pattern] = [a, b, a]
let array3: [Pattern] = [a, d, c]

array1 == array2  // true
array1 == array3  // false

最簡單的方法是為兩個模式陣列定義一個相等運算符,即

protocol Pattern
{
    func isEqualTo(other: Pattern) -> Bool
}

func ==(rhs: Pattern, lhs: Pattern) -> Bool
{
    return rhs.isEqualTo(lhs)
}

func ==(lhs: [Pattern], rhs: [Pattern]) -> Bool
{
    guard lhs.count == rhs.count else { return false }
    var i1 = lhs.generate()
    var i2 = rhs.generate()
    var isEqual = true
    while let e1 = i1.next(), e2 = i2.next() where isEqual
    {
        isEqual = e1 == e2
    }
    return isEqual
}

我定義了兩種符合Pattern的類型並嘗試了各種相等的比較,它都有效

struct Foo: Pattern
{
    let data: String
    init(data: String)
    {
        self.data = data
    }
    func isEqualTo(other: Pattern) -> Bool
    {
        guard let other = other as? Foo else { return false }
        return self.data == other.data
    }
}

struct Bar: Pattern
{
    let data: String
    init(data: String)
    {
        self.data = data
    }
    func isEqualTo(other: Pattern) -> Bool
    {
        guard let other = other as? Bar else { return false }
        return self.data == other.data
    }
}

let a = Foo(data: "jeremyp")
let b = Bar(data: "jeremyp")
let c = Foo(data: "jeremyp")
let d = Foo(data: "jeremy")

let comp1 = a == c // true
let comp2 = a == b // false
let comp3 = a == d // false

let array1: [Pattern] = [a, b, c]
let array2: [Pattern] = [a, b, a]
let array3: [Pattern] = [a, d, c]

let comp4 = array1 == array2 // true
let comp5 = array1 == array3 // false

斯威夫特回答:

protocol _Pattern
{
    func _isEqualTo(_other: Any) -> Bool?
}

extension _Pattern where Self: Pattern
{
    func _isEqualTo(_other: Any) -> Bool?
    {
        return (_other as? Self).map({ self.isEqualTo($0) })
    }
}

protocol Pattern: _Pattern, Equatable
{
    func isEqualTo(other: Self) -> Bool
}

extension Pattern
{
    func isEqualTo(other: _Pattern) -> Bool
    {
        return _isEqualTo(other) ?? false
    }
}

func == <T: Pattern>(rhs: T, lhs: T) -> Bool
{
    return rhs.isEqualTo(lhs)
}

這是我自己開發的一種模式 (雙關語),它對於這樣的情況非常有效。 _Pattern是一種自動實現的協議,由新的協議擴展功能提供,代表了一種類型擦除的Pattern版本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM