当元素类型为Protocol [Swift]时,无法在泛型Array类上调用扩展方法

时间:2015-09-23 13:31:45

标签: arrays swift generics protocols

根据评论中引用的错误消息,以下内容失败。它已被归结为最低限度,因此下面的代码没有明显的实用价值。我只是试图处理真正奇怪的(在我看来)错误消息。我想将数组声明为[P]而不是[S]的原因是数组内容的通常运行时多态性。

protocol P {
    func sp()
}

struct S: P {
    func sp() {}
}

extension Array where Element: P {
    func am() {}
}

func t() {
    let goodA = [S]()
    goodA.am() // No problem

    let badA = [P]()
    badA.am() // Error: '[P]' is not convertible to 'P'
}

1 个答案:

答案 0 :(得分:1)

协议声明定义了新的独立类型。尽管它们的行为与类,枚举和结构不同,但是它们可以充当变量或属性的类型(前提是没有相关的类型约束,但要坚持)。例如

protocol MyProtocol {}
let myConst: MyProtocol // myConst has type `MyProtocol`

在具有泛型where子句的协议扩展中,有两种不同的方法来约束所讨论的泛型类型:使用:_==。两者之间是有区别的。

使用:_

冒号指定泛型类型与指定的类型或协议匹配。它可以被解读为“继承自”或“符合”。例如,扩展名中指定的所有内容仅在关联类型符合Equatable或从SomeClass继承时才适用

protocol AnotherProtocol {
    associatedtype MyType
}

class SomeClass {}

extension AnotherProtocol where MyType: SomeClass {}
extension AnotherProtocol where MyType: Equatable {}

使用==

通用where子句中的==运算符指定通用类型完全等于指定的类型,而没有其他类型。下面的代码给出了编译时错误

class CustomType {}
class CustomTypeII: CustomType {}
class MyClass: AnotherProtocol { typealias MyType = CustomTypeII }

extension AnotherProtocol where MyType == CustomType {
    func myFunc() {}
}

let instance = MyClass()
instance.myFunc() // Error: `CustomTypeII` is not the same type as `CustomType`

不能使用==运算符 将泛型类型约束为具有关联类型的协议。编译器会抱怨该协议具有关联的类型要求。

protocol ThirdProtocol {}

extension ThirdProtocol where Self == AnotherProtocol {} // Error: `AnotherProtocol` has associated type requirements

从本质上讲,规范是模棱两可的:没有单一的AnotherProtocol类型,就像没有单一的Array类型一样。协议中的关联类型类似于通用类型的通用参数。在这里,需要使用冒号来指定通用类型“是某种” AnotherProtocol类型(不透明类型是由于需要指定具有关联类型约束的协议的特定“类型”,因此超出了问题)。

您的扩展程序

Array的扩展名仅适用于其元素为符合协议类型P的某种类型的数组实例,不适用于其元素为P的数组。不符合自己的协议类似于不继承自自己的类。

这是一个旧线程,但希望能有所帮助。