数组中的协议和关联类型
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()
}
编译没有问题。
我有协议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(参见 final
):
final class TreeNode: Node {
var parent: TreeNode? = nil
var children: [TreeNode] = []
}
和
func getReversedChildren<T: Node>(node: T) -> [T] {
return node.children.reversed()
}
编译没有问题。