我正在实现一个树模型。每种节点类型都可以选择多种功能。我正在使用基础class Node {}
来实现此功能,然后使用默认实现的许多协议来描述这些功能。然后,我有了从Node派生的并符合协议列表的最终类来描述我的结构。
每个协议具有以下样式的关联代码:
protocol Protocol {}
typealias ProtocolConformingNode = Node & Protocol
extension Node
{
public var isProtocolConforming: Bool {
return asProtocolConforming != nil
}
public var asProtocolConforming: ProtocolConformingNode? {
return self as? ProtocolConformingNode
}
}
我使用Node & Protocol
,以便可以对返回的项目使用其他与协议相关的查询,例如asOtherProtocolConforming
。
一切正常,直到我处理ProtocolConformingNode
的数组为止。最初,我在过滤节点+协议数组时遇到问题,我想在过滤后保持一致性:
extension Array where Element: Node
{
var someFilter: [Element] {
return self
}
}
let array = [ProtocolConformingNode]()
let filteredArray = array.someFilter
这会出现以下错误:
[ProtocolConformingNode]' (aka 'Array<Node & Protocol>') requires that 'ProtocolConformingNode' conform to 'AnyObject'
感觉有点奇怪,但是我认为它属于之前在SO上讨论过的一个问题:Protocol doesn't conform to itself?
我认为,对于我使用的这种罕见情况,所有协议的类型擦除都太多了,因此我对过滤后的节点转换感到满意。请注意,在以下代码中我没有使用Element
,而是显式使用了Node
和Element == Node
:
extension Array where Element == Node
{
var someFilter: [Node] {
return self
}
}
let array = [ProtocolConformingNode]()
let filteredArray = array.someFilter as! [ProtocolConformingNode]
现在出现错误:
'[ProtocolConformingNode]' (aka 'Array<Node & Protocol>') is not convertible to 'Array<Node>'
对我来说很奇怪。我可以使它像这样工作:
let filteredArray = (array as [Node]).someFilter as! [ProtocolConformingNode]
但是为什么我必须在这里投?以下内容如何运作?
var nodes = [Node]()
var protocolConformingNodes = [ProtocolConformingNode]()
nodes.append(contentsOf: protocolConformingNodes)
何时:
mutating func append<S>(contentsOf newElements: S) where Element == S.Element, S : Sequence
答案 0 :(得分:0)
这是与您链接的SO帖子相同的问题。特别是,您应该阅读Hamish的答案。 IMO,这是该语言的缺点,只有在Protocol
具有静态或初始化要求的情况下才是问题,而在这种情况下则没有。
快速而肮脏的解决方法是使用@objc
。完整的代码看起来像
class Node {}
@objc protocol Protocol {}
typealias ProtocolConformingNode = Node & Protocol
extension Array where Element: Node
{
var someFilter: [Element] {
return self
}
}
let array = [ProtocolConformingNode]()
let filteredArray = array.someFilter // Yay! No error this time.