考虑这段代码:
public protocol Evaluable {
typealias ReturnType
func eval(s: State) -> ReturnType
}
protocol AlgebraicExpr : Evaluable {
}
public struct Const : AlgebraicExpr {
var value: Int = 0
public func eval(s: State) -> Int {
return value
}
}
public struct Add : AlgebraicExpr {
let a, b: AlgebraicExpr
public func eval(s: State) -> Int {
return a.eval() + b.eval()
}
}
它无效,因为Add
无法拥有AlgebraicExpr
变量。
但我真的需要Add
来存储两个AlgebraicExpr
。你会如何在Swift中解决这个问题?
为了完整性,State
只是一个结构,例如:
public struct State {
var env = Dictionary<String, Int>()
init(_ d: Dictionary<String, Int> = [:]) {
env = d
}
subscript(s: String) -> Int? {
get {return env[s]}
set {env[s] = newValue}
}
}
答案 0 :(得分:3)
您无法存储依赖Self
或typealias
的两个协议,因为在抽象为协议时,功能尚未确定。如果不理解Evaluable
的值,ReturnType
类型没有实际意义,因此系统无法逻辑运行并了解应返回的内容。
以此为例(无效)
let thing: Evaluable = ...
let result = thing.eval(state) // What should return type be?
无法仅通过协议推断返回类型,它需要通过指定类型实现,通过定义typealias ReturnType
这些可以作为通用约束的原因是可以通过通用参数推断实现。
func genericConstrained<T: Evaluable>(evaluable: T, state: State) -> T.ReturnType {
return evaluable.eval(state)
}
在这个例子中,当我们在特定的符合对象上调用genericConstrained
时,可以推断出其所有其他功能。
<强> TL;博士强>
但是,如果你也限制你的包裹,你可以按照自己的意愿行事:
public struct Add<ExpressionType : AlgebraicExpr> : AlgebraicExpr {
let a, b: ExpressionType
public func eval(s: State) -> ExpressionType.ReturnType {
return a.eval() + b.eval()
}
}
然后使用
let add: Add<SomeConformingType> = ...