带有where子句的Swift Array扩展不适用于子协议

时间:2015-07-29 20:44:19

标签: swift swift-extensions swift-protocols

我已经编写了一些代码,我认为应该在Swift 2(Xcode 7b4)中工作,但它没有编译。我希望能够对我尝试做的事情是否有效有所了解。

请考虑此示例Array扩展名:

extension Array where Element: AnyObject {
    mutating func appendUniqueInstance(e: Element) {
        for element in self {
            if (element === e) {
                return
            }
        }

        self.append(e)
    }
}

首先,我的意思是一个元素为AnyObject的数组?基本上我说数组应该包含一组异类非值类型对象,可以比较实例相等(===)。

示例函数appendUniqueInstance()仅在元素已经存在于数组中时才将元素插入到数组中。这类似于Set insert()操作,但显然提供了排序,并且(更重要的是)并未强加Set的同类型要求(通过Equatable& #39;使用Self)。

如果我现在定义一个协议P和一个实现C的类P

protocol P : AnyObject {}

class C : P {}

并实例化C

let c = C()

然后这些非常明显的事情是真的:

let cIsAnyObject = c as AnyObject   // ok
let cIsP = c as P                   // ok

我现在可以做到以下几点:

var a1 = [AnyObject]()              // []

a1.appendUniqueInstance(c)          // [c]
a1.appendUniqueInstance(c)          // [c]

到目前为止,这么好,但现在针对问题案例:

var a2 = [P]()

a2.append(c)                        // ok, -> [c]

// Compiler error: Cannot invoke 'appendUniqueInstance' with an argument list of type '(C)'
a2.appendUniqueInstance(c)

此处,a2被输入为P的数组,因此append P的实例应该是完全有效的事情,事实上第a2.append(c)行符合我们的预期。

调用Array扩展函数appendUniqueInstance()会产生编译错误。

据我所知,编译器似乎对可以传递给appendUniqueInstance()并且没有意识到(或允许某些原因)C(通过P的内容感到困惑})是AnyObject

顺便提一下,如果我将P声明为:

@objc protocol P : AnyObject {}

然后一切都编译得很好,但我还必须确保协议P中的所有内容都符合@objc,这不是我想要的。

所以,在所有这一切之后,我的问题是:这看起来像应该有效吗?我希望它不仅仅是一个声明语法错误的情况,但我想如果它是的话我会很高兴。

2 个答案:

答案 0 :(得分:0)

如果您命令单击AnyObject,您会注意到它是符合@objc的协议。所以我猜这就是它要求使用@objc的原因。我注意到如果我们将C作为NSObject的子类,则不需要显式地从P实现方法以符合@objc

@objc protocol P : AnyObject {
    func hey()
}

class C : NSObject, P {
    func hey() {
        print("hey")
    }
}

答案 1 :(得分:0)

在我编写原始问题时编译器报告的错误似乎只是误导,而我试图获得的功能并不是(现在仍然不支持)Swift。

使用Xcode 8.2.1和Swift 3报告更准确的错误:

// error: using 'P' as a concrete type conforming
//   to protocol 'AnyObject' is not supported
a2.appendUniqueInstance(c)