数组中的协议和关联类型

Protocols and associated types in arrays

我有协议Node:

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

由classes实现:

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

但这会带来一个问题,因为访问 TreeNode 中的父级现在给我一个 Node,我想对它们执行 TreeNode 特定操作。所以我想将协议更改为:

protocol Node {
   associatedtype T: Node

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

让我将 class 定义为:

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

太棒了!但有一个陷阱。如果我想为 Node 编写处理数组的辅助方法:

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

编译器失败并出现错误: Cannot convert return expression of type 'ReversedCollection<[T.T]>' to return type '[T]'

根据我对这个问题的了解,我需要实现一种类型擦除机制来支持这个架构。但是如何在我的例子中做到这一点?

您可能希望节点的父节点和子节点与节点本身具有相同类型,而不仅仅是一些类型符合Node。那将是协议定义中的 Self

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

现在您可以定义具体的 class(参见 为什么 class 需要 final):

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

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

编译没有问题。