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