Swift:不能使用嵌套/链式泛型类型约束(策略模式)

时间:2016-03-25 23:57:03

标签: swift generics swift2 policy swift2.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的类型要求。

可能出现什么问题?

提前致谢! 彼得。

1 个答案:

答案 0 :(得分: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 :现在你想要更通用了。好的,但是你没有得到链类型依赖 WITHIN 泛型类型约束列表。类型约束必须直接解析。这应该使错误清楚:

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

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

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

  

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

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

BIG PICTURE

然而,我认为你在仿制药中纠缠不清,而忽略了简单地完成工作的想法。当您完全控制类型系统的那个分支时,通过泛型进行参数化是没有价值的,并且*您不需要返回 ACTUAL < / strong>函数*的泛化类型。

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

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

考虑:

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