繁体   English   中英

使用协议和关联类型的强类型树层次结构

[英]Strongly Typed Tree Hierarchy Using Protocols and Associated Types

我正在尝试使用协议设计对象的强类型层次结构,但不能完全正确。

为了说明,假设具体的类型,这将最终采用这些协议的 CountryStateCity

每个节点可以有一个父级(根对象除外)和/或子级(叶对象除外):所有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 ChildTypetypealias 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.

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