![](/img/trans.png)
[英]What is the purpose of using type parameters for an empty trait when extending it?
[英]Type bounds constraints restrictions in Higher Kinds when extending a trait
让我们设置问题条件
trait Bound
trait Bound2 extends Bound
trait T1[B <: Bound]
trait T2[B <: Bound2] extends T1[B]
trait WrapperT1[Tz[B2 <: Bound] <: T1[B2]]
此代码编译没有问题,尝试扩展WrapperT1
时出现问题
trait WrapperT2[Tz[B2 <: Bound2] <: T2[B2]] extends WrapperT1[T2]
// Compilator error
kinds of the type arguments (T2) do not conform to the expected kinds of the type parameters (type Tz) in trait WrapperT1.
[error] ex.T2's type parameters do not match type Tz's expected parameters:
[error] type B's bounds <: Bound2 are stricter than type B2's declared bounds <: ex.Bound
[error] trait WrapperT2[Tz[B2 <: Bound2] <: T2[B2]] extends WrapperT1[T2]
是的B2 <: Bound2
比B2 <: Bound
更严格,但我不明白为什么编译器会因为这个原因而抱怨,如果能了解更多信息,我将不胜感激。
trait Bound
trait Bound2 extends Bound
trait T1[B] {
implicit val ev: B <:< Bound
}
trait T2[B] extends T1[B] {
// this is possible thank's to covariance of class `<:<[-From, +To]` if i'm not wrong
implicit val ev: B <:< Bound2
}
trait WrapperT1[Tz[B2] <: T1[B2]]
// Compiles
trait WrapperT2[Tz[B2] <: T2[B2]] extends WrapperT1[Tz]
这看起来不错,我们保留了关于B2
泛型类型的编译检查,但是使用它有什么不方便的地方吗?
要理解编译器报错的原因,我们来看看这段代码(和你的代码一样,只是名字不同)
trait Show[A <: AnyRef] {
def show(a: A): Unit
}
trait ShowString[S <: CharSequence] extends Show[S] {
def show(s: S): Unit = println(s)
}
trait Wrapper1[S[A <: AnyRef] <: Show[A]] {
def show[A <: AnyRef](a: A)(implicit show: S[A]): Unit = show.show(a)
}
trait Wrapper2[S[C <: CharSequence] <: ShowString[C]] extends Wrapper1[S]
在这里,编译器也会发出错误type C's bounds <: CharSequence are stricter than type A's declared bounds <: AnyRef
,但我们假设你以某种方式让它在这里编译。 这意味着如果有人想使用你的包装器 class 来打印,比如说,一个列表,他们将无法做到这一点,这意味着你的包装器 class 基本上是无用的。
val w2: Wrapper[ShowString] = ???
w2.show(List(1, 2))
//Error: could not find implicit value for parameter show: ShowString[List[Int]]
在这种情况下,只是没有找到隐式。 但是,如果您在包装器中有一个接受S[_]
(或Tz[_]
,来自您的示例)的方法,并且您尝试将错误类型的 object 硬塞到您的show
方法中,您可能会遇到运行时异常。
它失败的原因与你不能这样做的原因相同
trait T1[A] {
def process(a: A): Unit
}
trait T2 extends T1[Int] {
def process(i: Int): Unit = ???
}
val t2: T2 = ???
t2.process("not an int")
T2
只是不具备处理任何非Int
的能力,这里同样适用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.