scala アプリケーションでリファクタリングを行っているときに、List から Set に変更すると、以前にはなかった問題が発生する状況に遭遇しました。分散についてはある程度の考えがありますが、コンパイラにとって正確に何を意味するのかを理解したいと思います。
私はこれに似たものを持っていました.これはコンパイルしてうまく動作します:
case class MyClassList(s: List[Any])
val myList = List(("this", false)) // List[(String, Boolean)]
val listWorks = MyClassList(myList)
次に、リストを次のように変更しました。
case class MyClassSet(s: Set[Any])
val mySet = Set(("this", false)) // Set[(String, Boolean)]
val setFails = MyClassSet(mySet)
この時点で、MyClassSet 型のオブジェクトを作成することは、Set を引数として渡すことで、それが Any の Set を受け入れる場合でも、もはや問題ありません。ここで、以下が機能すると少し混乱しました (セットは以前の mySet と「同じ」であることに注意してください)。
val setWorks1 = MyClassSet(Set(("this", false)))
簡単な説明は、コンパイラが mySet val を Set[(String, Boolean)] として推論しているということだと思いますが、setWorks1 の引数リストで直接インスタンス化すると、Set[Any] を受け入れるため、コンパイラはSet[Any] として推論します。これにより、最初の例は失敗し、2 番目の例は成功します。これらのものも機能します。これは、前のものが正しいことを示しています。
val setWorks2 = MyClassSet(mySet.toSet[Any])
val mySetOfAny: Set[Any] = Set(("this", false), ("that", true), ("other", false))
val setWorks3 = MyClassSet(mySetOfAny)
コンパイラによって表示される実際のエラーは次のとおりです。
Error:(15, 55) type mismatch;
found : Set[(String, Boolean)]
required: Set[Any]
Note: (String, Boolean) <: Any, but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: (...)
リストとセットは次のように定義されます。
type List[+A] = scala.collection.immutable.List[A]
type Set[A] = immutable.Set[A]
- この違いは、「Any よりも制限された型」の List を引数として渡すことを可能にするが、Set の場合は a ではないという型の分散の違いですか?
- この違いは、型間のキャストまたは変換を妨げているだけですか?
- これは主にコンパイラの「制限」ですか、それとも不変型の予想されるプロパティですか?
- 「実際には」不変型の間に他の違いはありますか、それともこのようなキャストに要約されますか?