【问题标题】:How to define an array of objects conforming to a protocol?如何定义符合协议的对象数组?
【发布时间】:2014-10-24 06:13:23
【问题描述】:

给定:

protocol MyProtocol {
    typealias T
    var abc: T { get }
}

还有一个实现 MyProtocol 的类:

class XYZ: MyProtocol {
    typealias T = SomeObject
    var abc: T { /* Implementation */ }
}

如何定义符合MyProtocol 的对象数组?

var list = [MyProtocol]()

给出(连同大量 SourceKit 崩溃)以下错误:

Protocol 'MyProtocol' can only be used as a generic constraint because it has Self or associated type requirements

尽管 typealias 实际上是在 MyProtocol 中定义的。

有没有办法让对象列表符合协议并具有通用约束?

【问题讨论】:

标签: ios cocoa-touch swift


【解决方案1】:

问题在于使用泛型对应的协议,类型别名。 听起来很奇怪,但是如果你定义了一个类型别名,你就不能将协议用作类型,这意味着你不能声明该协议类型的变量、函数参数等。你不能将它用作一个泛型对象数组。

正如错误所说,您可以将其用作通用约束(如class Test<T:ProtocolWithAlias>)。

为了证明这一点,只需从协议中删除类型别名(注意,这只是为了证明,它不是解决方案):

protocol MyProtocol {
    var abc: Int { get }
}

并相应地修改您的示例代码的其余部分:

class XYZ: MyProtocol {
    var abc: Int { return  32 }
}

var list = [MyProtocol]()

你会发现它有效。

您可能对如何解决这个问题更感兴趣。我想不出任何优雅的解决方案,只有以下2个:

  • 从协议中删除类型别名并将T替换为AnyObject(丑陋的解决方案!!)
  • 将协议转换为类(但这不是适用于所有情况的解决方案)

但正如你可能争辩的那样,我不喜欢其中任何一个。我能提供的唯一建议是重新考虑您的设计,并弄清楚您是否可以使用不同的方式(即不使用类型别名协议)来获得相同的结果。

【讨论】:

  • 如果你仔细想想,这实际上是有道理的。由于 abc 的返回类型在编译时是未知的,因此您无法以类型安全的方式可靠地使用结果。 MyProtocol 的数组没有意义,因为它们的功能并不相同。
  • @David:我不同意这一点。带有泛型的结构和类有同样的问题。其他语言(C#、java 等)允许使用泛型的协议。然而,MyProtocol 的数组确实具有相同的功能 - 不同的是每个元素可以以不同的方式实现功能 - 但相同的概念适用于使用基类作为数组元素类型并放置从它继承的对象的实例。
  • @Antonio 谢谢,我认为强制转换可能是这里唯一的解决方案。在我之前的尝试中,我确实使用了第一类泛型参数,但是 Swift 不允许(还)具有从泛型继承的非泛型类型 - 不允许使用 XYZ: ABC<Int>。
  • @erudel 是的,这是我想念的另一件 swift 的事情......虽然不如拥有 可用 通用协议重要。
猜你喜欢
  • 2023-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-02
  • 1970-01-01
  • 2017-04-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多