具有协议元素的数组无法调用数组扩展方法

时间:2019-02-20 04:32:53

标签: swift protocols

我想使带有协议元素的数组调用数组扩展方法。操场上的代码出现错误:

  

错误:类型'ObjectProtocol'不符合协议'Equatable'

代码:

extension Array {
    func good() {
    }
}

protocol ObjectProtocol {

}

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

extension Array where Element: Equatable {
    func bad() {}
}

var protocolArray = [ObjectProtocol]()
var array = [1,3,2,5]

array.good() // OK
array.bad() // OK

protocolArray.good() // OK
protocolArray.bad() // error: error: type 'ObjectProtocol' does not conform to protocol 'Equatable'

有什么方法可以实现?

3 个答案:

答案 0 :(得分:1)

您的Equatable一致性是Objective-C版本,而不是Swift版本。

protocol FoobarProtocol: Equatable {}

extension FoobarProtocol {
    public static func == (lhs: Self, rhs: Self) -> Bool {
        return true // do something useful
    }
}

您的问题是关于作为其他Array元素的协议。这将导致另一个错误:

  

错误:不支持将“ FoobarProtocol”用作符合协议“ Equatable”的具体类型

这是因为Equatable一致性只是在另一个协议上的一致性。 static func == (lhs:rhs:)的默认实现可能会给人以为它是完整的实现,但事实并非如此。 在采用具体类型的协议之前仍然是一个一致性。当在具体实现中使用该协议时,默认实现会自动唤醒。

简而言之: Swift中的协议不能等同。只能是具体类型。

替代选项

  1. 使用 struct 创建没有继承力的具体类型。
  2. 继承结合使用,而不是使用结构,因此您可以有几种具体的实现方式
  3. 创建一个包装对象,该对象具有协议类型的属性

答案 1 :(得分:0)

在Array扩展中实现的功能仅适用于相等类型。您在ObjectProtocol扩展中实现的函数也仅适用于相等类型,但这并不意味着符合ObjectProtocol的对象也将符合等同形式。为此,您可以执行以下操作:

class Custom<T: ObjectProtocol & Equatable>{
    var array = [T]()

    func doStuff(){
    array.bad()
    }
}

答案 2 :(得分:0)

如果您发现自己的错误,这很容易解释

  

错误:类型'ObjectProtocol'不符合协议'Equatable'

ObjectProtocol 扩展中,您添加了Self必须符合Equatable的约束。

解决方法是

protocol ObjectProtocol {}

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

extension Array where Element: Equatable {
    func bad() {
        print("I am bad")
    }
}

extension Array {
    func good() {
        print("I am good")
    }
}
// I have added a custom Type `Friend` and confirm it to the `ObjectProtocol` and Equatable
struct Friends: ObjectProtocol, Equatable{
    var years = 10
}

var protocolArray = [Friends]()
//protocolArray.append(Friends(name: 29))
//protocolArray.append(Friends(name: 50))
var array = [1, 3, 2, 5]

array.good() // OK
array.bad() // OK

protocolArray.good() // OK
protocolArray.bad() // It will work now