質問

Scala では、ジェネリック型引数に + や - などの分散演算子を使用して分散を定義できます。たとえば、 List type は標準ライブラリでは共変です。

class List[+A]

したがって、共変リストを持つ関数は次のように定義できます。

def foo[A](list : List[A])

また、分散は一般的な境界を使用してエミュレートできます。したがって、これも書くことができます

def foo[A](list : List[_:< A])

もちろんこれには意味がないので、 list はすでに共変です。ただし、共変ではない型にも同じトリックを実行できます。(のように Stack)。もちろん、共変のスタック (集約の継承) から新しい型を作成することもできます。

そこで私の質問:

  1. 分散に一般的な境界を使用する必要があるのはどのような場合ですか?そして、いつ新しい共変型を作成すべきでしょうか?
  2. 一般的な境界は分散にのみ役立つのでしょうか、それともさらに多くのこと (言語概念) を宣言できますか。
  3. 境界が分散のためにのみ役立つのであれば、境界は Java との互換性のためにのみ使用されるのでしょうか?

事前にね:)

役に立ちましたか?

解決

型が自然に共変または反変である場合は、そのように宣言する必要があります。ユーザーはあなたに感謝するでしょう。実際、使用場所の違いは主に Java に起因します。より正確には、次のようなタイプです。 Array[T <: Number] は、存在型の短縮形として扱われます。

ArrayBuffer[T] forSome { type T <: Number }

Scala では、存在型の構文が非常に大きくなります。あまり使用しないことを推奨しているため、これはある意味意図的なものです。実存型が必要になるのはどのような場合ですか?

  1. ワイルドカードを使用して Java 型の類似物を記述するには、次のようにします。 List<? extends Number>.
  2. Java の raw 型に相当するものを記述するには、次のようにします。 List.

Java では、生の型とワイルドカード型は全く同じではなく、どちらも存在型と全く同じではありません (それらが何でないのかはわかっていても、正確に何であるかを説明するのは非常に困難です)。しかし、実際にはそれらは実存型に十分近いため、Scala はそれらをこの種の型にマッピングすることを回避します。

他のヒント

  1. 新しいジェネリック型、たとえば Foo[T] を作成するときは、その型が共変、反変、不変のいずれであるかを一生懸命判断し、それぞれ Foo[+T]、Foo[-T]、または Foo[T] と宣言する必要があります。確かに、これは少し難しいかもしれません。ただし、Foo のユーザーは、ジェネリック境界を使用することで、Foo を使用する必要があるたびにその決定を下す必要がなくなります。要するに:分散が型自体のプロパティである場合は、呼び出しサイトの分散よりも宣言サイトの分散を優先します。

ところで、Martin Odersky、Lex Spoon、Bill Venners による『Programming in Scala』の本には、分散に関する素晴らしいセクションがいくつかあります。第 19 章「型パラメータ化」を参照してください。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top