[英]Type class and implicits with singleton type/case object
I am trying to implement a type class that works with case objects instead of classes.我正在尝试实现一个使用 case 对象而不是类的类型类。 It kind of works.它有点工作。 When I pass the case object itself to the function it works, however, when I try to pass an object with the type of the base trait it doesn't compile.但是,当我将 case 对象本身传递给它可以工作的函数时,当我尝试传递具有基本特征类型的对象时,它不会编译。
object Test {
sealed trait MyType
case object Type1 extends MyType
case object Type2 extends MyType
trait Builder[A] {
def build: String
}
object Builder {
implicit val type1Builder: Builder[Type1.type] = new Builder[Type1.type] {
def build: String = s"building1"
}
implicit val type2Builder: Builder[Type2.type] = new Builder[Type2.type] {
def build: String = s"building2"
}
def build[A](a: A)(implicit builder: Builder[A]) = builder.build
}
import Builder._
// Compiles
def test[T <: MyType](t:Type2.type): Unit = {
println(Builder.build(t))
}
// Doesn't compile - 'could not find implicit value for parameter builder '
def test2[T <: MyType](t:MyType): Unit = {
println(Builder.build(t))
}
}
That's because type parameters in scala are Invariant by default, this means that:那是因为 scala 中的类型参数默认是不变的,这意味着:
Builder[Type1.type] is not a subtype of Builder[MyType]. Builder[Type1.type] 不是 Builder[MyType] 的子类型。
In this block of your code, you need a Builder[MyType], and neither type1Builder nor type2Builder are subtypes of Builder[MyType]:在这段代码中,您需要一个 Builder[MyType],并且 type1Builder 和 type2Builder 都不是 Builder[MyType] 的子类型:
def test[T <: MyType](t:MyType): Unit = {
println(Builder.build(t))
}
You can make Builder's type parameter covariant (Builder[+A]), but then, both type1Builder and type2Builder will be candidates for that implicit, so it will fail again.您可以使 Builder 的类型参数协变 (Builder[+A]),但是 type1Builder 和 type2Builder 都将成为隐式的候选对象,因此它将再次失败。
What you need to do is use a Context bound in your test method, instead of an upper type bound, as follows:您需要做的是在您的测试方法中使用 Context 绑定,而不是类型上限,如下所示:
def test[T : Builder](t: T): Unit = {
println(Builder.build(t))
}
This means that test receives a T type, that is a member of Builder type class, both Type1 and Type2 are members of Builder type class since there is a Builder[Type1.type] and a Builder[Type2.type] in implicit scope.这意味着 test 接收到一个 T 类型,即 Builder 类型类的成员,Type1 和 Type2 都是 Builder 类型类的成员,因为在隐式作用域中有一个 Builder[Type1.type] 和一个 Builder[Type2.type]。
If you also want to limit test so you can only call it with implementations of MyType
, you can use both an upper type bound and a context bound:如果您还想限制测试,以便只能使用MyType
实现调用它,则可以同时使用类型上限和上下文范围:
def test[T <: MyType : Builder](t: T): Unit = {
println(Builder.build(t))
}
test(Type1) // building1
test(Type2) // building2
Somehow this worked for me.不知何故,这对我有用。 Not sure why不知道为什么
def test2[T <: MyType : Builder ](t2:T): Unit = {
println(Builder.build(t2))
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.