2

我在 Swift 中实现了一个随机树数据结构。为了约束树的宽度和深度,我决定使用策略(策略)模式

我的政策如下所示:

protocol BaseTreeNodePolicy {
    static var maximumDepth: Int { get }
    static var maximumWidth: Int { get }
}

我有一个看起来像这样的基类:

class BaseTreeNode<PolicyType: BaseTreeNodePolicy> { /* ... */ }

它的一些子类:

class ValueNode<ValueType, PolicyType: BaseTreeNodePolicy>: BaseTreeNode<PolicyType> { /* ... */ }
class ActionNode<PolicyType: BaseTreeNodePolicy>: BaseTreeNode<PolicyType> { /* ... */ }

在我添加这个类之前,一切都运行良好:

final class SequenceNode<ChildType: ActionNode<PolicyType>, PolicyType: BaseTreeNodePolicy>: ActionNode<PolicyType> {
    public var sequence: [ChildType] = []
    // ...
    public override func addRandomDescendants(generator: EntropyGenerator, maxDepth: Int) {
        // ...
        sequence.reserveCapacity(42)
        // ...
        let descendant = ChildType(generator: generator, maxDepth: maxDepth - 1)
        // ...
    }
}

编译时SequenceNode,我在这一行得到编译器错误:

// 'ChildType' is not a subtype of 'ActionNode<PolicyType>'
sequence.reserveCapacity(42)

而这一行:

// Type 'PolicyType' does not conform to protocol 'BaseTreeNodePolicy'
let descendant = ChildType(generator: generator, maxDepth: maxDepth - 1)

我不知道出了什么问题,因为我在声明的标题部分清楚地说明了类型ChildType: ActionNode<PolicyType>要求PolicyType: BaseTreeNodePolicy

有什么问题?

提前致谢!彼得。

4

1 回答 1

3

编辑:重做以达到您的意图:

ActionNode<PolicyType>不属于参数列表。您只是在参数化PolicyType

final class SequenceNode<PolicyType: BaseTreeNodePolicy> {
    typealias ChildType = ActionNode<PolicyType>
    var sequence = [ChildType]()
    func addRandomDescendants(generator: EntropyGenerator, maxDepth: Int) {
        sequence.reserveCapacity(42)
    }
}

编辑 2:现在你想要更通用。好的,但是您不会在泛型类型约束列表中链接类型依赖。类型约束必须是可直接解析的。这应该使错误清楚:

class _ERROR_SequenceNode<PolicyType, ChildType where PolicyType: BaseTreeNodePolicy, ChildType: ActionNode<PolicyType>> { }

超类约束“ActionNode”不能依赖于类型参数

但是,您不能使用BaseTreeNodePolicy代替,PolicyType因为它不是具体的:

不支持使用“BaseTreeNodePolicy”作为符合协议“BaseTreeNodePolicy”的具体类型

因此,由于ChildType已经受到泛型类型的约束,因此该泛型类型必须是可直接实例化的,因此它本身只能受到已知的外部具体实现的约束BaseTreeNodePolicy

大图

但是,我认为您正在纠结于泛型,而忽略了简单地完成工作的想法。当您完全控制类型系统的该分支时,通过泛型进行参数化没有任何价值,并且*您不需要从函数返回ACTUAL泛型类型*。

换句话说,我必须构建一个哈希表,在FooKeyTypewhere上进行一般参数化,FooKeyType: Hashable因为我的类的用户理所当然地期望函数的返回值是他​​们getKey()代码中的实际类型,而不是 type 。在这里,您永远不会返回该对象,或者即使您这样做了,您也不应该关心它的返回类型是固定的,而不是某个特定的、具体的策略类型。HashablepolicyBaseTreeNodePolicy

您可以简单地通过将存储的属性抽象类型约束为必要的协议来进行约束。

考虑:

protocol BaseTreeNodePolicy {
    var maximumDepth: Int { get }
    var maximumWidth: Int { get }
}

class BaseTreeNode {
    var policy: BaseTreeNodePolicy

    required init(policy: BaseTreeNodePolicy) {
        self.policy = policy
    }

    // Use 'policy' anywhere now. You've defined a protocol, don't generically parameterize
}

class ValueNode: BaseTreeNode {
    required init(policy: BaseTreeNodePolicy) {
        super.init(policy: policy)
    }
}

class ActionNode: BaseTreeNode {
    required init(policy: BaseTreeNodePolicy) {
        super.init(policy: policy)
    }
}

class SequenceNode<ChildType: ActionNode>: BaseTreeNode {
    var sequence: [ChildType] = []

    required init(policy: BaseTreeNodePolicy) {
        super.init(policy: policy)
    }

    func addRandomDescendants() {
        let c = ChildType(policy: policy)
        sequence.reserveCapacity(42)
    }
}

class FooNode: ActionNode {}

class MyPolicy: BaseTreeNodePolicy {
    var maximumDepth = 3
    var maximumWidth = 5
}

let s = SequenceNode<FooNode>(policy: MyPolicy())
于 2016-03-26T00:26:54.113 回答