キー

2012-01-06 5 views
6
ため

をダイナミックミックスインタイプを使用してマップにメンバーを追加することはできません次の文は、罰金コンパイルし、期待どおりに動作:キー

val map : Map[_ >: Int with String, Int] = Map(1 -> 2, "Hello" -> 3) 

しかし、私はマップに追加しようとした場合:

map + ((3,4)) 

または

map + (("Bye", 4)) 

はその後、私は型の不一致を取得します

が見つかりました:私はAnyとして許可するように型シグネチャをのInt文字列

と弱体化した場合:java.lang.Stringで( "さようなら")必要

:タイプ_ $ 1>のをどこ_ $ 1キーのタイプ、これはすべて期待どおりに動作します。

私の直感は、これはMapのキータイプの非可変性と関係しており、_ $ 1は何らかの形で特定のスーパータイプInt with Stringとして修正されていますが、特にこれには満足していません。誰が何が起こっているか説明できますか?

編集に追加する:

val map = if (true) Map(1 -> 2) else Map("1" -> 2) 

答えて

9

あなたはInt with Stringを誤解:

をこれが生じた場所を迷っている場合、それはあなたが何かをすれば取得署名です。これはIntとStringの連合ではなく、交点であり、IntとStringの場合は空です。文字列である値のセットでIntである値のセットではなく、文字列の特性でIntの特性を持つ値のセットでもあります。そのような値はありません。

Either[Int, String]を使用し、Map[Left(1) -> 2, Right("Hello") -> 3)を使用できます。どちらも[連合]ではないが、A U Bではなく、差別化された連合であるA + Bである。[Int、Int]はIntと同じではないという違いを把握できる。実際には(Int、Boolean)と同型です:あなたはIntを持っていますが、あなたはどちらの側もそれを知っています。 AとBが互いに素(IntとStringのように)であるとき、A + BとA U Bは同形である。

または(心臓のかすかなものではない)あなたはMiles Sabinのa possible encoding of union typesを見ることができます。 (私はあなたが実際にクラスマップを使ってそれを使うことができないと確信していますが、あなたが試してみるよりもあまり確かではありませんが、読書は最も読書的です)。


編集Int with Stringバウンドあなたの下

、あなたの質問およびコードあまりにも速くを読んで申し訳ありませんので Map[_ >: Int with String, Int]、バウンド Map[_ >: Nothing, Int]と同じ低い Nothingようで、 Nothingと同じです暗黙のうちに、これは Map[_, Int]です。実際の MapMap[Any, Int]です。あなたはブール型のキーを追加することもできました。 Map[Any, Int]Map[_, Int]とタイプすることができますので、val宣言が機能します。しかし、あなたの入力はキーのタイプに関するすべての情報を失います。キーの種類がわからない場合は、テーブルから何も追加(または取得)することはできません。

UpperBoundの方が良いとは言えませんでしたが、可能なキーはありません。最初のval宣言でさえ失敗します。


編集2if (true) Map(1 -> 2) else Map("1" -> 2)

に関するこれはMap(1 -> 2, "1" -> 2)と同じものではありません。それは簡単で、単純にMap[Any, Int]となりました。は、より一般的な上位タイプのIntStringです。

一方、Map(1 -> 2)Map[Int, Int]であり、Map["1", 2]Map[String, Int]である。 Map[Int, Int]Map[String, Int]の共通のスーパータイプを見つける問題は、共通のスーパータイプIntStringを見つけることができません。

実験をしましょう。 Mapは、その第2パラメータにおいて共変である。あなたが値ではなく、キーとしてIntStringを使用する場合:

if (true) Map(1 -> 2) else Map(1 -> "2") 
res1: scala.collection.immutable.Map[Int, Any] 

共分散では、それは単に、すべての型パラメータの共通スーパータイプになります。反変タイプでは

BAのサブタイプである場合には

class L[-T] 
object L{def apply[T](t: T) = new L[T]) 
class A 
class B extends A 
class C 
if (true) L(new A) else L(new C) 
res2: L[A with C] 
if (true) L(new A) else L(new B) 
res3: L[B] 

はそれが交差点A with C.をとり、BAはちょうどBです。

は今、地図の非変異体のパラメータを持つ2つのタイプが関連している

if (true) Map(new A -> 1) else Map(new B -> 1) 
res4: scala.collection.immutable.Map[_ >: B <: A, Int] 

このようなタイプでは役に立ちません。タイプBのキーで値にアクセスしたり、値を追加したりすることができます。しかし、キーAの値にアクセスすることはできません。これはあなたが実際のマップ(trueのために)にあるように、厳しい運があります。 keySetにアクセスすると、Set[A]と入力されます。キーのタイプに関する情報が不完全で、できることは限られていますが、これは地図のタイプに関する知識が限られているため、必要な制限です。 Int and Stringでは最小限の情報が得られ、下限はAny、上限はNothingに相当します。 Nothing上限は、パラメータとしてキーをとるルーチンを呼び出すことができません。 Set[Any]Anyが下限であるkeySetを引き続き取得できます。

+0

これは問題ではないと思います。「Int with String」は、キー自体のタイプではなく、キーのタイプにバインドされています。他の多くの状況でそれを縛りとして使うことができます。 – Submonoid

+0

ユニオンタイプのエンコーディングは素晴らしいことですが、特に質問には関係ありません。特に、私は割り当てが有効な理由に興味がありますが、他のものを追加しようとすると失敗します。 – Submonoid

+0

私はそれが完全に役に立たないと思っています。 –