簡體   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