gpt4 book ai didi

swift - 使用协议(protocol)和关联类型的强类型树层次结构

转载 作者:行者123 更新时间:2023-11-30 12:10:44 25 4
gpt4 key购买 nike

我正在尝试使用协议(protocol)设计一个强类型的对象层次结构,但不太正确。

为了说明这一点,假设最终采用这些协议(protocol)的具体类型是CountryState城市

每个节点都可以有一个父节点(根对象除外)和/或子节点(叶对象除外):所有 State 实例都是单个 Country 实例的子节点并将其作为父级,并且将 City 实例作为子级,等等。

所以我从这两个协议(protocol)开始:

/// 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 }
}

我有两个单独的协议(protocol),而不是一个将所有上述要求分组的协议(protocol),因为我不想为该协议(protocol)指定一个“虚拟”typealias ParentType根类Country(无意义),也不是叶类City的“虚拟”typealias ChildType

相反,我可以分离父子行为,并让中间类 State 采用两种协议(protocol)。

<小时/>

下一步,我想通过从磁盘读取的字典来初始化我的类。对于子类,我想在实例化时指定父类,所以我想出了这个方案:

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)
})
}
}

...因为在此协议(protocol)中,ChildType 被限制为 UnarchivableChild,所以它应该支持初始化程序...?但我得到:

Cannot invoke 'ChildType' with an argument list of type '(dictionary: ([String : Any]), parent: Self)'

(为什么要大写“Self”?)

我认为我遗漏了一些关于关联类型如何工作的信息......

如何编写此默认实现的代码?

<小时/>

更新:显然,传递 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
})
}
}

错误是:

Cannot assign value of type 'Self' to type '_?'

最佳答案

阅读完The Swift Programmng Language: Generics后(部分:“使用 GenerciWhere 子句进行扩展”),我找到了适当的语法来实现我想要的。我选择了这段代码(类型名称与原始问题中的类型名称略有不同):

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 指定为其值。

或者,我可以更改:

protocol ParentNode {
associatedtype ChildType: AnyObject

至:

protocol ParentNode {
associatedtype ChildType: ChildNode

...并跳过第二个约束。

关于swift - 使用协议(protocol)和关联类型的强类型树层次结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46093448/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com