Scala中如何在类型类内使用依赖类型?
解决Scala类型类中依赖类型约束的问题
你的问题核心在于,ServerSideFun[C]中的f方法不需要额外的泛型参数A和B——因为对于特定的C,A和B已经被Dep[C]的隐式实例唯一确定了。原来的泛型写法让编译器无法推断出42就是对应的B类型,因为泛型B可以是任意类型(只要存在匹配的Dep.Aux[C,A,B]),这就导致了类型不匹配错误。
正确的实现思路
我们可以直接在ServerSideFun[C]中关联Dep[C]的类型成员,让f方法的输入输出类型严格遵循Dep定义的映射:
修改
ServerSideFuntrait的定义:
利用Scala的依赖类型,直接引用Dep[C]的A和B类型,同时通过隐式参数引入Dep[C]的实例(保证对于C存在对应的类型映射)。调整类型类实例:
实例中不需要再写泛型参数,直接使用Dep[C]对应的A和B类型实现f方法。
修改后的完整代码
object Rextester extends App { println("Hello, World!3") // 定义View类型 trait View1 trait View2 // 定义类型级映射Dep trait Dep[C] { type A type B } object Dep { type Aux[C0, A0, B0] = Dep[C0] { type A = A0; type B = B0 } implicit object DepInstanceView1 extends Dep[View1] { type A = String type B = Int } implicit object DepInstanceView2 extends Dep[View2] { type A = String type B = String } } // 定义类型类ServerSideFun,绑定Dep的类型成员 trait ServerSideFun[C] { // 引入Dep[C]的隐式实例,直接使用其A和B类型 def f(a: Dep[C]#A)(implicit dep: Dep[C]): Dep[C]#B } // 标准实现 object ServerSideFun { implicit object View1Conv extends ServerSideFun[View1] { def f(a: Dep[View1]#A)(implicit dep: Dep[View1]): Dep[View1]#B = 42 } implicit object View2Conv extends ServerSideFun[View2] { def f(a: Dep[View2]#A)(implicit dep: Dep[View2]): Dep[View2]#B = "42" } } // 替代实现 object ServerSideFunAlternativeImplementation { implicit object View1Conv extends ServerSideFun[View1] { def f(a: Dep[View1]#A)(implicit dep: Dep[View1]): Dep[View1]#B = 43 } implicit object View2Conv extends ServerSideFun[View2] { def f(a: Dep[View2]#A)(implicit dep: Dep[View2]): Dep[View2]#B = "43" } } // 测试验证 import ServerSideFun._ val view1Fun: ServerSideFun[View1] = implicitly println(view1Fun.f("test")) // 输出42 import ServerSideFunAlternativeImplementation._ val view1AltFun: ServerSideFun[View1] = implicitly println(view1AltFun.f("test")) // 输出43 }
进一步优化:简化代码写法
如果你觉得Dep[C]#A的写法不够简洁,可以用类型别名来简化:
// 优化后的ServerSideFun trait ServerSideFun[C] { // 用类型别名简化依赖类型的引用 type A = Dep[C]#A type B = Dep[C]#B def f(a: A)(implicit dep: Dep[C]): B } // 实例中的写法也会更简洁 implicit object View1Conv extends ServerSideFun[View1] { def f(a: A)(implicit dep: Dep[View1]): B = 42 }
这样所有ServerSideFun[C]的实例都必须严格遵循Dep中定义的C -> (A,B)映射,完全满足你的核心需求。
内容的提问来源于stack exchange,提问作者jhegedus
相关产品推荐
相关产品推荐

