如何解决“协议......只能用作通用约束......”

时间:2016-01-12 23:02:51

标签: swift protocols

考虑这段代码:

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}
    }
}

1 个答案:

答案 0 :(得分:3)

您无法存储依赖Selftypealias的两个协议,因为在抽象为协议时,功能尚未确定。如果不理解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> = ...