简体   繁体   中英

Protocols and associated types in arrays

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.

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