繁体   English   中英

扩展特征时,类型边界约束限制在更高种类中

[英]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 <: Bound2B2 <: 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM