16

一般的なサブタイピングに混乱しています。

Java では、 typeAが のサブタイプである場合B、ジェネリック型C<A>でありC<B>、不変です。たとえば、ArrayList<Base>は のサブタイプではありませんArrayList<Derived>

ただし、Scala では、ジェネリック型C<A>とは、型が のサブタイプであるC<B>場合、共変です。では、Scala にはあるが Java にはないジェネリック クラスのプロパティは何ですか?AB

4

1 に答える 1

42

最初に、分散はジェネリック型パラメーターのプロパティであり、パラメーター化された型自体のプロパティではないことに注意してください。

第二に、あなたはscalaについて間違っています - 型パラメータはデフォルトで不変です。調べてみましょう!

ジャワ

Java には、ユース サイト分散アノテーションがあります。つまり、次のようにメソッドを宣言できます。

boolean addAll(Collection<? extends T> c);

ただし、型パラメーターが共変である「パラメーター化された型」(私はこの用語を大まかに使用しています) の 1 つの形式があります: Java 配列です! (配列は変更可能であり、型システムを簡単に回避できるため、これは実際には正気ではありません)。次の点を考慮してください。

public static void subvert(Object[] arr) { arr[0] = "Oh Noes!"; }

その後:

Integer[] arr = new Integer[1];
subvert(arr); //this call is allowed as arrays are covariant
Integer i = arr[0];

良いインタビューの質問:これはどうなりますか?

スカラ

Scala では、宣言サイトの分散があります。つまり、型パラメーターのバリアンスは、パラメーターと一緒に宣言されます (注釈+とを使用-)。

trait Function1[-I, +O]

これは、トレイトFunction1に 2 つの型パラメーターがIあり、Oそれぞれ反変と共変であることを示しています。注釈が宣言されていない場合+/-型パラメータは不変です。たとえば、 Set はその型パラメーターで不変です。

scala> def foo(set: Set[Any]) = ()
foo: (set: Set[Any])Unit

scala> Set(1)
res4: scala.collection.immutable.Set[Int] = Set(1)

scala> foo(res4)
<console>:10: error: type mismatch;
 found   : scala.collection.immutable.Set[Int]
 required: Set[Any]
Note: Int <: Any, but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
              foo(res4)
                  ^

ただし、リストは共変として宣言されています。

scala> def bar(list: List[Any]) = ()
bar: (list: List[Any])Unit

scala> List(1)
res6: List[Int] = List(1)

scala> bar(res6)

コンパイラに聞いてみませんか?

これを実証する別の方法は、サブタイプの証拠をコンパイラに直接要求することです。

scala> class Cov[+A]
defined class Cov

scala> implicitly[Cov[Int] <:< Cov[Any]]
res8: <:<[Cov[Int],Cov[Any]] = <function1>

ただし、不変の型パラメーターを使用する

scala> class Inv[A]
defined class Inv

scala> implicitly[Inv[Int] <:< Inv[Any]]
<console>:9: error: Cannot prove that Inv[Int] <:< Inv[Any].
              implicitly[Inv[Int] <:< Inv[Any]]
                        ^

最後に、反変性:

scala> class Con[-A]
defined class Con

scala> implicitly[Con[Any] <:< Con[Int]]
res10: <:<[Con[Any],Con[Int]] = <function1>

識別子も参照<:<

于 2012-05-13T14:58:03.220 に答える