I have a protocol 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. 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:
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]'
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
. That would be Self
in the protocol definition:
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
):
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.