次の特性があるとします。
trait OuterTrait {
type InnerType
}
これで非ジェネリック関数を書くことができますsomeAlgo
:
def pairToString[S, U](x: S, y: U): String =
"{" + y.toString + " in " + x.toString + "}"
def pairPrintln[S, U](x: S, y: U) {
println(pairToString(x, y))
}
def someAlgo(x: OuterTrait)(y: x.InnerType): x.InnerType = {
pairPrintln(x, y)
y
}
および一連の汎用関数:
def someAlgoObjObj[T <: OuterTrait](x: T)(y: x.InnerType): x.InnerType = {
pairPrintln(x, y)
y
}
def someAlgoObjType[T <: OuterTrait](x: T)(y: x.InnerType): T#InnerType = {
pairPrintln(x, y)
y
}
def someAlgoTypeType[T <: OuterTrait](x: T)(y: T#InnerType): T#InnerType = {
pairPrintln(x, y)
y
}
そして、もう 1 つの一般的な関数がコンパイルされません。
def someAlgoTypeObj[T <: OuterTrait](x: T)(y: T#InnerType): x.InnerType = {
pairPrintln(x, y)
y
}
1)someAlgo
とsomeAlgoObjObj
が最も正しい関数です。2) この例でジェネリック関数を使用する意味はまったくありません。
そして、上記のジェネリック関数のいくつかの違いを明確にしたいと思います。私が間違いを犯した場合は、私を修正してください。
したがって、私が理解しているように、タイプT
は静的タイプx
(それを呼び出すX
)またはジェネリックコールの明示的なタイプ(algo[Int]
たとえば)に対応します。そのためT#InnerType
、 type の宣言で type に対応しX
ます。のstatic型にx.InnerType
も対応しています。違いはどこにありますか?InnerType
x
さらに...someAlgoObjType
コンパイルされるので、のサブタイプx.InnerType
である必要があるようです。ダウンキャストを暗黙的に行うことはできないため、コンパイルしなくても問題ありません。最後のものを書き直すことができますが:T#InnerType
someAlgoTypeObj
def someAlgoTypeObj[T <: OuterTrait](x: T)(y: T#InnerType): x.InnerType = {
pairPrintln(x, y)
y.asInstanceOf[x.InnerType]
}
UPD1:明示的な型パラメーターでそれらを使用する場合someAlgoObjObj
との違いが1つ見つかりました。someAlgoTypeType
拡張するクラスを書くとOuterTrait
:
class OuterIntClass extends OuterTrait{
type InnerType = Int
}
val x: OuterIntClass = new OuterIntClass()
val y: Int = 5
それで:
someAlgoObjObj[OuterTrait](x)(y) // OK
そして次の呼び出しは機能しません:
someAlgoTypeType[OuterTrait](x)(y)