Bla*_*son 1 scala existential-type higher-kinded-types
当我遇到这个问题时,我试图用更高种类和类型的边界来玩.我的用例是我希望能够使用Request的任何子类型或Request类型本身来参数化GenericAction实例.Action trait使用默认类型Request扩展GenericAction特征(在这种情况下,只会生成Request的匿名实例).
trait Request[+A]
trait GenericAction[A, R[_] <: Request[_]]
trait Action[A] extends GenericAction[A, Request]
trait ActionBuilderBase[R[_] <: Request[_], G[_] <: GenericAction[_,R]]
Run Code Online (Sandbox Code Playgroud)
ActionBuilderBase具有与子特征ActionBuilder和ActionBuilder2共享的实用程序方法.ActionBuilder生成默认的Action [A]和Request [A]实例.
trait ActionBuilder extends ActionBuilderBase[Request,Action]
Run Code Online (Sandbox Code Playgroud)
到目前为止一切都那么好,但是当我尝试创建另一个使用R和GenericAction子类扩展ActionBuilderBase的特性时(在这种情况下会创建GenericAction的匿名实例),它无法编译.我想原因是在第一个ActionBuilder的情况下,请求类型已经被"填充"(因为Action [A]已经有一个请求类型== Request),这与下面的示例不同.为了让这个例子有效,我需要"填写"什么?
//Fails with "GenericAction takes two type parameters, expected: one" - what should the type annotation for GenericAction look like?
trait ActionBuilder2[R[_] <: Request[_]] extends ActionBuilderBase[R,GenericAction]
Run Code Online (Sandbox Code Playgroud)
在这种情况下,能够写出这样的东西会很好:
trait ActionBuilder2[R[_] <: Request[_]] extends
ActionBuilderBase[R, GenericAction[_, R]]
Run Code Online (Sandbox Code Playgroud)
表示您想部分申请GenericAction.不幸的是,这不是有效的Scala语法(虽然Erik Osheim有一个编译器插件,可以让你写一些非常相似的东西).
但是,您可以使用"type lambda trick":
trait ActionBuilder2[R[_] <: Request[_]] extends
ActionBuilderBase[R, ({ type L[A] = GenericAction[A, R] })#L]
Run Code Online (Sandbox Code Playgroud)
有关其工作原理的详细说明,请参阅此答案.