Swift: 不能使用 nested/chained 通用类型约束(策略模式)
Swift: Can't use nested/chained generic type constraints (Policy pattern)
我正在 Swift 中实现随机树数据结构。为了限制树的宽度和深度,我决定使用 策略(策略)模式。
我的政策是这样的:
protocol BaseTreeNodePolicy {
static var maximumDepth: Int { get }
static var maximumWidth: Int { get }
}
我有一个基础 class,看起来像这样:
class BaseTreeNode<PolicyType: BaseTreeNodePolicy> { /* ... */ }
它的一些子class:
class ValueNode<ValueType, PolicyType: BaseTreeNodePolicy>: BaseTreeNode<PolicyType> { /* ... */ }
class ActionNode<PolicyType: BaseTreeNodePolicy>: BaseTreeNode<PolicyType> { /* ... */ }
一切正常,直到我添加这个 class:
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)
我不知道有什么问题,因为我在声明的 header 部分清楚地说明了 ChildType: ActionNode<PolicyType>
和 PolicyType: BaseTreeNodePolicy
的类型要求。
有什么问题吗?
提前致谢!
彼得
编辑:重做以实现您的意图:
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>> { }
Superclass constraint 'ActionNode' cannot depend on a type parameter
但是,您 ALSO 不能使用 BaseTreeNodePolicy
代替 PolicyType
,因为它不具体:
Using 'BaseTreeNodePolicy' as a concrete type conforming to protocol 'BaseTreeNodePolicy' is not supported
因此,由于 ChildType
已经受到泛型类型的约束,该泛型类型必须 可直接实例化 ,因此它本身只能受到已知类型的约束, 外, 具体 实现 BaseTreeNodePolicy
.
大图
但是,我认为您正在纠结于泛型,同时错过了简单地完成工作的想法。当您完全控制类型系统的那个分支并且*您不需要return 时,通过泛型进行参数化没有任何价值 ACTUAL 来自函数的通用类型*。
换句话说,我必须在 FooKeyType
上构建一个散列 table,其中 FooKeyType: Hashable
一般参数化,因为我的 class 的用户理所当然地期望 return来自 getKey()
函数的值是 他们的 代码中的实际类型,而不是 Hashable
类型。在这里,您永远不会 return policy
对象,或者即使您这样做了,您也不应该关心它的 return 类型固定为 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())
我正在 Swift 中实现随机树数据结构。为了限制树的宽度和深度,我决定使用 策略(策略)模式。
我的政策是这样的:
protocol BaseTreeNodePolicy {
static var maximumDepth: Int { get }
static var maximumWidth: Int { get }
}
我有一个基础 class,看起来像这样:
class BaseTreeNode<PolicyType: BaseTreeNodePolicy> { /* ... */ }
它的一些子class:
class ValueNode<ValueType, PolicyType: BaseTreeNodePolicy>: BaseTreeNode<PolicyType> { /* ... */ }
class ActionNode<PolicyType: BaseTreeNodePolicy>: BaseTreeNode<PolicyType> { /* ... */ }
一切正常,直到我添加这个 class:
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)
我不知道有什么问题,因为我在声明的 header 部分清楚地说明了 ChildType: ActionNode<PolicyType>
和 PolicyType: BaseTreeNodePolicy
的类型要求。
有什么问题吗?
提前致谢! 彼得
编辑:重做以实现您的意图:
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>> { }
Superclass constraint 'ActionNode' cannot depend on a type parameter
但是,您 ALSO 不能使用 BaseTreeNodePolicy
代替 PolicyType
,因为它不具体:
Using 'BaseTreeNodePolicy' as a concrete type conforming to protocol 'BaseTreeNodePolicy' is not supported
因此,由于 ChildType
已经受到泛型类型的约束,该泛型类型必须 可直接实例化 ,因此它本身只能受到已知类型的约束, 外, 具体 实现 BaseTreeNodePolicy
.
大图
但是,我认为您正在纠结于泛型,同时错过了简单地完成工作的想法。当您完全控制类型系统的那个分支并且*您不需要return 时,通过泛型进行参数化没有任何价值 ACTUAL 来自函数的通用类型*。
换句话说,我必须在 FooKeyType
上构建一个散列 table,其中 FooKeyType: Hashable
一般参数化,因为我的 class 的用户理所当然地期望 return来自 getKey()
函数的值是 他们的 代码中的实际类型,而不是 Hashable
类型。在这里,您永远不会 return policy
对象,或者即使您这样做了,您也不应该关心它的 return 类型固定为 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())