简体   繁体   English

数组中的协议和相关类型

[英]Protocols and associated types in arrays

I have a protocol Node : 我有一个协议Node

protocol Node {
   var parent: Node?
   var children: [Node]
}

which is implemented by classes: 通过类实现:

class TreeNode: Node {
   var parent: Node?
   var children: [Node]
}

But this poses a problem as accessing the parent in TreeNode now gives me a Node , and I want to do TreeNode specific operations on them. 但这带来了一个问题,因为现在访问TreeNode的父级会给我一个Node ,并且我想对它们执行TreeNode特定的操作。 So I want to change the protocol to: 所以我想将协议更改为:

protocol Node {
   associatedtype T: Node

   var parent: T?
   var children: [T]
}

Which let's me define the class as: 让我将类定义为:

class TreeNode: Node {
   var parent: TreeNode?
   var children: [TreeNode]
}

Great! 大! But there's a catch. 但是有一个陷阱。 If I want to write a helper method for Node that deals with arrays: 如果我想为Node编写一个处理数组的辅助方法:

func getReversedChildren<T: Node>(node: T) -> [T] {
   return node.children.reversed()
}

The compiler fails with the error: Cannot convert return expression of type 'ReversedCollection<[TT]>' to return type '[T]' 编译器失败,并显示以下错误: Cannot convert return expression of type 'ReversedCollection<[TT]>' to return type '[T]'

From what I can gather about this issue, I need to achieve a type-erasure mechanism to support this architecture. 从我可以收集的有关此问题的信息来看,我需要实现一种类型擦除机制来支持此体系结构。 But how can this be done on my example? 但是如何在我的示例中做到这一点?

You probably want the parent and children of a node to be of the same type as the node itself, not just some type conforming to Node . 您可能希望节点的父级和子级与节点本身具有相同的类型 ,而不仅仅是与Node 某种类型。 That would be Self in the protocol definition: 在协议定义中将是Self

protocol Node {
    var parent: Self? { get set }
    var children: [Self] { get set }
}

Now you can define the concrete class (see A Swift protocol requirement that can only be satisfied by using a final class for why the class needs to be final ): 现在,您可以定义具体的类(请参阅Swift协议要求,该类只能通过使用final类来满足,以了解为什么该类需要为final ):

final class TreeNode: Node {
    var parent: TreeNode? = nil
    var children: [TreeNode] = []
}

and

func getReversedChildren<T: Node>(node: T) -> [T] {
    return node.children.reversed()
}

compiles without problems. 编译没有问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM