[英]Strongly Typed Tree Hierarchy Using Protocols and Associated Types
我正在尝试使用协议设计对象的强类型层次结构,但不能完全正确。
为了说明,假设具体的类型,这将最终采用这些协议的类 Country
, State
和City
。
每个节点可以有一个父级(根对象除外)和/或子级(叶对象除外):所有State
实例都是单个Country
实例的子级,并以其为父级,而City
实例为子级,依此类推。
因此,我从以下两个协议开始:
/// To be adopted by State and City
///
protocol Child: AnyObject {
associatedtype ParentType: AnyObject
// (-> so that property `parent` can be weak)
weak var parent: ParentType? { get }
}
/// To be adopted by Country and State
///
protocol Parent: AnyObject {
associatedtype ChildType: AnyObject
// (-> for symmetry)
var children: [ChildType] { get }
}
我有两个单独的协议,而不是将所有上述要求归为一组的协议,因为我不想为根类Country
指定“虚拟” typealias ParentType
(这是没有意义的),也typealias ChildType
为typealias ChildType
“ dummy” typealias ChildType
。叶类City
。
相反 ,我可以将父行为和子行为分开,只是让中间类State
采用两种协议。
接下来 ,我想根据从磁盘读取的字典来初始化我的句点。 对于子类,我想在实例化时指定父类,因此我想出了以下方案:
protocol UnarchivableChild: Child {
init(dictionary: [String: Any], parent: ParentType?)
}
protocol UnarchivingParent: Parent {
associatedtype ChildType: UnarchivableChild
func readChildren(fromDictionaries dictionaries: [[String: Any]]) -> [ChildType]
}
就目前而言,看起来我可以更进一步,并添加方法readChildren(fromDictionaries:)
的默认实现,如下所示:
extension UnarchivingParent {
func readChildren(fromDictionaries dictionaries: [[String: Any]]) -> [ChildType] {
return dictionaries.flatMap({ dictionary in
return ChildType(dictionary: dictionary, parent: self)
})
}
}
...由于此协议中, ChildType
被限制为UnarchivableChild
,因此它应支持初始化程序...? 但是我得到:
无法使用类型为'(dictionary:([[String:Any]),parent:Self)'的参数列表调用'ChildType'
(为什么大写的“ Self”?)
我想我缺少有关关联类型如何工作的信息...
如何编码此默认实现?
更新:显然,以某种方式超越自我是问题所在。 我将代码修改为:
protocol Node: AnyObject {
}
protocol Parent: Node {
associatedtype ChildNodeType: Node
var children: [ChildNodeType] { get set }
}
protocol Child: Node {
associatedtype ParentNodeType: Node
weak var parent: ParentNodeType? { get set }
}
protocol UnarchivableChild: Child {
init(dictionary: [String: Any]) // Removed parent parameter!
}
protocol UnarchivingParent: Parent {
associatedtype ChildNodeType: UnarchivableChild
func readChildren(fromDictionaries dictionaries: [[String: Any]]) -> [ChildNodeType]
}
extension UnarchivingParent {
func readChildren(fromDictionaries dictionaries: [[String: Any]]) -> [ChildNodeType] {
return dictionaries.flatMap({
let child = ChildNodeType(dictionary: $0)
// Assign parent here instead:
child.parent = self // < ERROR HERE
return child
})
}
}
错误是:
无法将类型“ Self”的值分配给类型“ _?”
在阅读了Swift编程语言:泛型 (部分:“带有Generci Where子句的扩展”)之后,我找到了实现所需功能的适当语法。 我选择了以下代码(类型名称与原始问题中的类型名称有所不同):
protocol DictionaryInitializable {
init(dictionary: [String: Any])
}
protocol ChildNode: AnyObject {
associatedtype ParentType: AnyObject
weak var parent: ParentType? { get set }
}
protocol ParentNode {
associatedtype ChildType: AnyObject
var children: [ChildType] { get set }
}
// This 'WHERE' clause fixes the issue:
extension ParentNode where ChildType: DictionaryInitializable,
ChildType: ChildNode, ChildType.ParentType == Self {
func readChildren(from dictionaries: [[String: Any]]) -> [ChildType] {
return dictionaries.map({
return ChildType(dictionary: $0)
})
}
}
where子句的第一个约束条件让我调用初始化程序init(dictionary:)
,第二个约束条件保证存在属性parent
,第三个self
让我将self
赋值为它的值。
另外,我可以更改:
protocol ParentNode {
associatedtype ChildType: AnyObject
至:
protocol ParentNode {
associatedtype ChildType: ChildNode
...并跳过第二个约束。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.