2016-08-19 16 views
3

なぜコンパイラはt1 ++ t2の結果をList [Any]として扱うのですか?タイプSの2つのリストを連結すると、タイプSのリストだけが返されます。スカラ汎用サブタイプパラメータ

// compiles 
def cons[S <: List[Any]](t1: S, t2: S): S = t1 

// type mismatch; found List[Any] required S 
def cons[S <: List[Any]](t1: S, t2: S): S = t1 ++ t2 

答えて

3

ここに私は起こっていると信じています。まず、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は正しくIntDoubleのための最も近い共通の祖先を発見し、それがAnyValだ見ることができるように。この場合、SAnyValです。

今度はこれを試してみましょう:

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を見つけ出す必要があります。後で適用する場所ではありません(Bconsの空きパラメータではありません)。唯一の情報は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) 

なぜこの仕事をしますか?ここでt1t2の両方が同じタイプであっても、Sであっても(後でSを推測することもできます)。したがってB == Sとなり、結果はList[S]になります。この場合も、SIntDoubleの最も近い共通祖先です。

+0

3番目の例では、「ここでは、t1とt2の両方が、Sが何であっても、まったく同じ型を持っています」と言います。どのようにすることができますか?リスト[Int]リスト[Double]は異なるタイプではありませんか? – Samar

+0

私は混乱が生じると思います。なぜなら、さまざまな型を最初に引数として渡すことができますが、Sの型は渡された異なる型の最も近い共通の祖先になるからです。 – Samar

+0

私はサマールの質問に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

1

List[Any] ++ List[Any]Sを保証するものではありませんList[Any]で、List[Any]のサブタイプもS ++ SのプロパティがSで持っているので、コンパイラはList[Any]にフォールバックします。

+0

私はビクターの答えが実際に何が起こっているかを明確にしていると思います。私は100%確信していませんが、実際の引数t1/t2がconsメソッドに渡されたとき、渡された引数の型は、最も近い共通の祖先にトレースされ、Sの型です。引き数の型で渡されます。 – Samar