【问题标题】:Can't call extension method on generic Array class when element type is a Protocol [Swift]当元素类型是协议 [Swift] 时,无法在泛型 Array 类上调用扩展方法
【发布时间】:2015-09-23 13:31:45
【问题描述】:

根据评论中引用的错误消息,以下失败。它已经被归结为最低限度,因此下面的代码没有明显的实用价值。我只是想处理真正奇怪的(在我看来)错误消息。我想将数组声明为[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'
}

【问题讨论】:

  • 认为有一个类似的问题,但我还没有找到。答案是协议不符合自身。
  • 或者显然,任何父协议(这样protocol Q: P {} 不能解决任何问题);我是否错过了关于where 子句只能由具体类型满足的一致性的更深层次的观点?

标签: arrays swift generics protocols


【解决方案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 类型的数组。不符合自身的协议类似于不从自身继承的类。

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

【讨论】:

  • 这是一个很好的答案!也许只是为 OPs 问题添加一个直接的解决方案。例如,他们可以创建protocol PParent {}。然后,他们所要做的就是让P 继承自PParent 并将where 子句更改为where Element: PParent。不过很好的解释,+1!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-13
  • 2016-07-06
  • 1970-01-01
  • 2014-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多