如何解决“协议……只能作为通用约束……" [英] how to solve "Protocol ... can only be used as a generic constraint..."
问题描述
考虑这段代码:
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
变量.
it is invalid because Add
cannot have an AlgebraicExpr
variable.
但我真的需要 Add
来存储两个 AlgebraicExpr
.你会如何在 Swift 中解决这个问题?
But I really need Add
to store two AlgebraicExpr
s. How would you solve this in Swift?
为了完整性,State
只是一个结构体,例如:
For completeness, State
is just a struct, for example:
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}
}
}
推荐答案
你不能存储两个依赖于 Self
的协议,或者一个 typealias
因为当抽象为协议,功能未定.如果不了解 ReturnType
的值,类型 Evaluable
没有实际意义,因此系统不可能逻辑地运行并了解应该返回什么.
You can't store two protocols that rely on Self
, or a typealias
because when abstracted as a protocol, the functionality is undetermined. Type Evaluable
has no real meaning without understanding the value of ReturnType
, so it's not possible for the system to function logically and understand what should be returned.
以这样的事情为例(无效)
Take for instance something like this (not valid)
let thing: Evaluable = ...
let result = thing.eval(state) // What should return type be?
不能单独通过协议推断返回类型,它需要指定类型的实现,通过定义typealias ReturnType
The return type can't be inferred through the protocol alone, it requires an implementation by a specified type that gives more knowledge about its behavior by defining the typealias ReturnType
这些可以作为泛型约束的原因是可以通过泛型参数推断实现.
The reason these can function as generic constraints is that the implementation can be inferred through the generic parameters.
func genericConstrained<T: Evaluable>(evaluable: T, state: State) -> T.ReturnType {
return evaluable.eval(state)
}
在此示例中,当我们对特定的符合条件的对象调用 genericConstrained
时,可以推断出它的所有其他功能.
In this example, when we call genericConstrained
on a particular conforming object, all of its other functionality can be inferred.
tl;dr
但是,如果您还限制了您的包,您可以随心所欲:
If however, you also constrain your package, you could do as you wish:
public struct Add<ExpressionType : AlgebraicExpr> : AlgebraicExpr {
let a, b: ExpressionType
public func eval(s: State) -> ExpressionType.ReturnType {
return a.eval() + b.eval()
}
}
然后使用like
let add: Add<SomeConformingType> = ...
这篇关于如何解决“协议……只能作为通用约束……"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!