ここに私は起こっていると信じています。まず、S
はです。どこでも同じ種類のマジックはありません。最初の例を見てみましょう:
scala> def cons[S <: List[Any]](t1: S, t2: S): S = if(t1.isEmpty) t1 else t2
cons: [S <: List[Any]](t1: S, t2: S)S
scala> cons(List(1), List(2.0))
res21: List[AnyVal] = List(2.0)
あなたはScalaは正しくInt
とDouble
のための最も近い共通の祖先を発見し、それがAnyVal
だ見ることができるように。この場合、S
はAnyVal
です。
今度はこれを試してみましょう:
scala> def cons[S <: List[Any]](t1: S, t2: S): S = t1 ++ t2
<console>:11: error: type mismatch;
found : List[Any]
required: S
def cons[S <: List[Any]](t1: S, t2: S): S = t1 ++ t2
^
間違っているのですか?このエラーメッセージは、S
の代わりに++
の結果が何らかの形でList[Any]
であることを意味します。何故ですか?さんは++
署名(簡略化され、実際の署名が長い)を見てみましょう:
def ++[B >: A](other: List[B]): List[B] = ???
ので、ScalaはA
の最も近い祖先とother
の実際の型パラメータを見つける必要があります。唯一の問題は、cons
を定義した時点でB
を見つけ出す必要があります。後で適用する場所ではありません(B
はcons
の空きパラメータではありません)。唯一の情報はS
の上限で、それはList[Any]
なので、B
の定義ポイントのcons
の唯一の安全なソリューションは、Any
です。つまり、++
の結果はList[Any]
であり、それはS
に適合しません。したがって、エラー。
第三例:
scala> def cons[S <: Any](t1: List[S], t2: List[S]): List[S] = t1 ++ t2
cons: [S](t1: List[S], t2: List[S])List[S]
scala> cons(List(1), List(1.0))
res0: List[AnyVal] = List(1, 1.0)
なぜこの仕事をしますか?ここでt1
とt2
の両方が同じタイプであっても、S
であっても(後でS
を推測することもできます)。したがってB == S
となり、結果はList[S]
になります。この場合も、S
はInt
とDouble
の最も近い共通祖先です。
3番目の例では、「ここでは、t1とt2の両方が、Sが何であっても、まったく同じ型を持っています」と言います。どのようにすることができますか?リスト[Int]リスト[Double]は異なるタイプではありませんか? – Samar
私は混乱が生じると思います。なぜなら、さまざまな型を最初に引数として渡すことができますが、Sの型は渡された異なる型の最も近い共通の祖先になるからです。 – Samar
私はサマールの質問に2分の1を付けます。私は '(t1:S、t2:S)'と '(t1:リスト[S]、t2:リスト[S]) 'の間に違いは見当たりません。どちらの場合も、t1とt2は全く同じタイプです。もちろん、あなたは 'List [Int]'と 'List [String]'を渡すことができますが、その場合、最も近い祖先は 'List [Any] 'なので' S'です。あなたは 'def cons [S <:List [Any]](t1:S、t2:S):S'の例を提供することができますか?あなたが渡すものは、コンパイラは 'S'を最も近い祖先と推論し、**は返されるものです**。推論された型 'S'。 'S'で動作するはずです。 – slouc