6

次の特性があるとします。

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)someAlgosomeAlgoObjObjが最も正しい関数です。2) この例でジェネリック関数を使用する意味はまったくありません。

そして、上記のジェネリック関数のいくつかの違いを明確にしたいと思います。私が間違いを犯した場合は、私を修正してください。

したがって、私が理解しているように、タイプT静的タイプx(それを呼び出すX)またはジェネリックコールの明示的なタイプ(algo[Int]たとえば)に対応します。そのためT#InnerType、 type の宣言で type に対応しXます。のstatic型にx.InnerTypeも対応しています。違いはどこにありますか?InnerTypex

さらに...someAlgoObjTypeコンパイルされるので、のサブタイプx.InnerTypeである必要があるようです。ダウンキャストを暗黙的に行うことはできないため、コンパイルしなくても問題ありません。最後のものを書き直すことができますが:T#InnerTypesomeAlgoTypeObj

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)
4

2 に答える 2

0

T#InnerTypeは、「あるT に属する InnerType」をx.InnerType意味し、「(OuterTrait型の)特定の x に属する InnerType」を意味します。

ここでこれらを理解する上での鍵は、特定の xにおけるいくつかの T対にあります。一部を一部の Tと解釈することはできますが、どの T インスタンスを解釈するかはわかりません。つまり、2 つの T が必ずしも同じであるとは限らないため、T#InnerType が別の T#InnerType と等しいことを証明することはできません。

署名を分析しましょう。

/* 1 */ def someAlgoObjObj[T <: OuterTrait](x: T)(y: x.InnerType): x.InnerType = ???
/* 2 */ def someAlgoObjType[T <: OuterTrait](x: T)(y: x.InnerType): T#InnerType = ???
/* 3 */ def someAlgoTypeType[T <: OuterTrait](x: T)(y: T#InnerType): T#InnerType = ???
  1. x と、この xに属する InnerType を指定すると、その InnerType が返されます。
  2. x と、この xに属する InnerType を指定すると、一部の Tに属する InnerType が返されます。これは、一部の Tが必ずしも x と同じインスタンスであるとは限らないことを意味します。
  3. ある Tに属する x と InnerType を指定すると、あるTに属する InnerType が返されます

4つ目は次のとおりです。

def someAlgoTypeObj[T <: OuterTrait](x: T)(y: T#InnerType): x.InnerType = y

署名は次のとおりです。 x とTに属する InnerType を指定すると、この xに属する InnerType が返されます。しかし、実装では、必ずしも x と同じではない T に属する y を返そうとするため、コンパイラは文句を言います。

于 2013-06-23T17:15:01.873 に答える
0

updateについて少し注意してください。

someAlgoTypeType[OuterTrait](x)(y) 

メソッドの署名が、そのyパラメーターが型に準拠することを期待していてT#InnerType、あなたy.typeが Int であることを示しているため、失敗します。機能させるには、タイプを次のように変更する必要があります。

class OuterIntClass extends OuterTrait{
  type InnerType = Int
}
val x: OuterIntClass = new OuterIntClass()
val y: x.InnerType = 5

Nowyの型は型射影T#InnerTypeを満たし、someAlgoTypeType[OuterTrait](x)(y)コンパイルします

于 2013-06-24T06:33:55.730 に答える