Swift 2添加协议与协议的一致性

时间:2022-12-24 21:16:40

Can I add protocol conformance to a protocol via a swift extension?

我可以通过快速扩展将协议一致性添加到协议中吗?

//Plain old protocol here
protocol MyData {
    var myDataID: Int { get }
}

I want to make the MyData protocol equatable by default (just compare the ID)

我想默认使MyData协议相等(只需比较ID)

extension MyData : Equatable { }

But I get this lovely error:

但我得到了这个可爱的错误:

"Extension of protocol 'MyData' cannot have an inheritance clause"

“协议扩展'MyData'不能有继承子句”

The behavior i'm looking is BananaData conforming to Equatable (a protocol) because it implements the MyData protocol which can provide a default implementation of Equatable

我正在寻找的行为是符合Equatable(协议)的BananaData,因为它实现了MyData协议,它可以提供Equatable的默认实现

//This is the method to implement Equatable
func ==(lhs: MyData, rhs: MyData) -> Bool {
    return lhs.myDataID == rhs.myDataID
}

struct BananaData: MyData {
    var myDataID: Int = 1
}

func checkEquatable(bananaOne: BananaData, bananaTwo: BananaData) {
    //This compiles, verifying that BananaData can be compared
    if bananaOne == bananaTwo { }
    //But BananaData is not convertible to Equatable, which is what I want
    let equatableBanana = bananaOne as Equatable
    //I don't get the additional operations added to Equatable (!=)
    if bananaOne != bananaTwo { } //Error
}

2 个解决方案

#1


23  

As the error message says: an extension of a protocol cannot have an inheritance clause. Instead, you could make MyData protocol inherit from Equatable in the original declaration.

正如错误消息所示:协议的扩展不能具有继承子句。相反,您可以在原始声明中使MyData协议继承自Equatable。

protocol MyData: Equatable {
    var myDataID: Int { get }
}

You could then extend add an implementation of == for types that conform to MyData:

然后,您可以为符合MyData的类型扩展添加==的实现:

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

However, I would highly not recommend this! If you add more properties to conforming types, their properties won't be checked for equality. Take the example below:

但是,我强烈不推荐这个!如果向符合类型添加更多属性,则不会检查其属性是否相等。以下面的例子为例:

struct SomeData: MyData {
    var myDataID: Int
    var myOtherData: String
}

let b1 = SomeData(myDataID: 1, myOtherData: "String1")
let b2 = SomeData(myDataID: 1, myOtherData: "String2")

b1 == b2 // true, although `myOtherData` properties aren't equal.

In the case above you'd need to override == for SomeData for the correct result, thus making the == that accepts MyData redundant.

在上面的情况中,您需要为SomeData重写==以获得正确的结果,从而使接受MyData的==变为冗余。

#2


2  

Does this playground do what you want? I made it based on what I understand from Protocol-Oriented Programming in Swift from WWDC 2015.

这个游乐场能做你想做的吗?我是根据我从WWDC 2015中的Swift中面向协议编程中所理解的内容来完成的。

import Foundation

//Plain old protocol here

func == (lhs: MyData, rhs: MyData) -> Bool {
    return lhs.myDataID == rhs.myDataID
}

func != (lhs: MyData, rhs: MyData) -> Bool {
    return lhs.myDataID != rhs.myDataID
}

protocol MyData {
    var myDataID: Int { get }
}

extension MyData where Self: Equatable {

}


struct BananaData: MyData {
    var myDataID: Int = 1
}

func checkEquatable(bananaOne: BananaData, bananaTwo: BananaData) {
    //This compiles, verifying that BananaData can be compared
    if bananaOne == bananaTwo {
        print("Same")
    }
    //But BananaData is not convertible to Equatable, which is what I want
    //I don't get the additional operations added to Equatable (!=)
    print(bananaOne.myDataID)
    print(bananaTwo.myDataID)


    if bananaOne != bananaTwo {

    }

    //Error


}

let b1 = BananaData(myDataID: 2)
let b2 = BananaData(myDataID: 2)

checkEquatable(b1, bananaTwo: b2)

let c = b1 == b2  // Evaluates as true

#1


23  

As the error message says: an extension of a protocol cannot have an inheritance clause. Instead, you could make MyData protocol inherit from Equatable in the original declaration.

正如错误消息所示:协议的扩展不能具有继承子句。相反,您可以在原始声明中使MyData协议继承自Equatable。

protocol MyData: Equatable {
    var myDataID: Int { get }
}

You could then extend add an implementation of == for types that conform to MyData:

然后,您可以为符合MyData的类型扩展添加==的实现:

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

However, I would highly not recommend this! If you add more properties to conforming types, their properties won't be checked for equality. Take the example below:

但是,我强烈不推荐这个!如果向符合类型添加更多属性,则不会检查其属性是否相等。以下面的例子为例:

struct SomeData: MyData {
    var myDataID: Int
    var myOtherData: String
}

let b1 = SomeData(myDataID: 1, myOtherData: "String1")
let b2 = SomeData(myDataID: 1, myOtherData: "String2")

b1 == b2 // true, although `myOtherData` properties aren't equal.

In the case above you'd need to override == for SomeData for the correct result, thus making the == that accepts MyData redundant.

在上面的情况中,您需要为SomeData重写==以获得正确的结果,从而使接受MyData的==变为冗余。

#2


2  

Does this playground do what you want? I made it based on what I understand from Protocol-Oriented Programming in Swift from WWDC 2015.

这个游乐场能做你想做的吗?我是根据我从WWDC 2015中的Swift中面向协议编程中所理解的内容来完成的。

import Foundation

//Plain old protocol here

func == (lhs: MyData, rhs: MyData) -> Bool {
    return lhs.myDataID == rhs.myDataID
}

func != (lhs: MyData, rhs: MyData) -> Bool {
    return lhs.myDataID != rhs.myDataID
}

protocol MyData {
    var myDataID: Int { get }
}

extension MyData where Self: Equatable {

}


struct BananaData: MyData {
    var myDataID: Int = 1
}

func checkEquatable(bananaOne: BananaData, bananaTwo: BananaData) {
    //This compiles, verifying that BananaData can be compared
    if bananaOne == bananaTwo {
        print("Same")
    }
    //But BananaData is not convertible to Equatable, which is what I want
    //I don't get the additional operations added to Equatable (!=)
    print(bananaOne.myDataID)
    print(bananaTwo.myDataID)


    if bananaOne != bananaTwo {

    }

    //Error


}

let b1 = BananaData(myDataID: 2)
let b2 = BananaData(myDataID: 2)

checkEquatable(b1, bananaTwo: b2)

let c = b1 == b2  // Evaluates as true