scala - GenericsにおけるAnyとUnderscoreの比較
質問
Scalaの以下のGenericsの定義はどう違うのでしょうか?
class Foo[T <: List[_]]
と
class Bar[T <: List[Any]]
私の直感では、両者はほぼ同じですが、後者の方がより明示的だと思います。前者がコンパイルされ、後者がコンパイルされないケースを発見していますが、正確な違いについて私の指を置くことができません。
ありがとうございます。
編集してください。
もう一人混ぜてもいいですか?
class Baz[T <: List[_ <: Any]]
どのように解決するのですか?
OK、私はコメントを投稿する代わりに、それについて私の考えを持つべきだと思いました。申し訳ありませんが、これは長くなるので、TL;DRが必要な場合は、最後まで読み飛ばしてください。
Randall Schulzが言ったように、ここで
_
は実存的な型の省略形です。すなわち
class Foo[T <: List[_]]
の省略形です。
class Foo[T <: List[Z] forSome { type Z }]
Randall Shulzの回答が言及していることに反して(完全な開示:この記事の以前のバージョンで私も間違っていました、指摘してくれたJesper Nordenbergに感謝します)、これは同じではないことに注意してください。
class Foo[T <: List[Z]] forSome { type Z }
と同じでもない。
class Foo[T <: List[Z forSome { type Z }]]
Randall Shulzの回答で参照された記事の著者は自分でも間違えていて(コメント参照)、後で修正したそうなので、注意してください。この記事の主な問題は、示されている例では、存在詞の使用によって型付けの問題から解放されるはずなのに、そうなっていないことです。コードをチェックして、コンパイルしてみてください。
compileAndRun(helloWorldVM("Test"))
または
compileAndRun(intVM(42))
. そう、コンパイルできないのです。単に
compileAndRun
で一般的な
A
を使えば、コードはコンパイルできるようになり、よりシンプルになります。
要するに、この記事は存在詞とそれが何のためにあるのかを学ぶのに最適な記事ではないでしょう(著者自身、コメントでこの記事は整理する必要があると認めています)。
ですから、私はむしろこの記事を読むことをお勧めします。 http://www.artima.com/scalazine/articles/scalas_type_system.html 特に "Existential types" と "Variance in Java and Scala" と名付けられたセクションを読むことをお勧めします。
この記事から得られるべき重要なポイントは、非共変型を扱うときに、(汎用Javaクラスを扱えることとは別に)実存型が有用であるということです。 以下はその例です。
case class Greets[T]( private val name: T ) {
def hello() { println("Hello " + name) }
def getName: T = name
}
このクラスは一般的なものですが(不変であることにも注意してください),このクラスは
hello
とは異なり)型パラメータを全く使っていません。
getName
とは異なり)、もし私が
Greets
を呼び出すことができるはずです。
T
が何であれ、常に呼び出せるようにしなければなりません。 を受け取るメソッドを定義したい場合
Greets
インスタンスを受け取り、その
hello
メソッドを呼び出すだけなので、これを試すことができます。
def sayHi1( g: Greets[T] ) { g.hello() } // Does not compile
案の定、これはコンパイルされません。
T
がここでいきなり出てくるからです。
よし、じゃあメソッドを汎用的にしてみよう。
def sayHi2[T]( g: Greets[T] ) { g.hello() }
sayHi2( Greets("John"))
sayHi2( Greets('Jack))
素晴らしい、これは動作します。ここで存在証明も使えます。
def sayHi3( g: Greets[_] ) { g.hello() }
sayHi3( Greets("John"))
sayHi3( Greets('Jack))
も動作します。というわけで、全体として、実存的な(例えば
sayHi3
のように)、型パラメータ(例えば
sayHi2
).
しかし、これは
Greets
がそれ自身を別のジェネリッククラスへの型パラメータとして表示する場合、これは変わります。の複数のインスタンスを保存したいとします。
Greets
のインスタンス (異なる
T
を使うことができます。試してみましょう。
val greets1: Greets[String] = Greets("John")
val greets2: Greets[Symbol] = Greets('Jack)
val greetsList1: List[Greets[Any]] = List( greets1, greets2 ) // Does not compile
最後の行はコンパイルされません。
Greets
は不変なので
Greets[String]
となり
Greets[Symbol]
として扱うことはできません。
Greets[Any]
としても
String
と
Symbol
はどちらも
Any
.
では、実存的なものを使って、省略記法でやってみましょう。
_
:
val greetsList2: List[Greets[_]] = List( greets1, greets2 ) // Compiles fine, yeah
これでうまくコンパイルされ、期待通りに、できるようになりました。
greetsSet foreach (_.hello)
さて、そもそも型チェックの問題が発生したのは
Greets
は不変である。もし、これが共変クラス(
class Greets[+T]
) になっていれば、すべてがうまくいき、存在格子は必要なかったでしょう。
まとめると、存在情報はジェネリックな不変クラスを扱うのに便利ですが、ジェネリッククラスがそれ自身を別のジェネリッククラスへの型パラメータとして表示する必要がない場合、存在情報は必要なく、単にメソッドに型パラメータを追加すればうまくいく可能性があります。
さて、あなたの具体的な質問に戻ります(やっと、わかりました!)。
class Foo[T <: List[_]]
なぜなら
List
は共変量なので、これはどう考えてもただ言っているのと同じです。
class Foo[T <: List[Any]]
というわけで、この場合、どちらの表記を使うかは、本当にスタイルの問題です。
しかし、もし
List
を
Set
で、物事は変わります。
class Foo[T <: Set[_]]
Set
は不変であるため、このままでは
Greets
クラスと同じ状況になります。したがって、上記は本当に
class Foo[T <: Set[Any]]
関連
-
[解決済み] List<Dog> は List<Animal> のサブクラスですか?Java のジェネリックはなぜ暗黙のうちに多相性にならないのですか?
-
[解決済み] Scalaのオブジェクトとクラスの違い
-
[解決済み】Scalaにおける中括弧と括弧の正式な違い、また、どのような場合に使用すべきなのか?
-
[解決済み】Scala。抽象型とジェネリックス
-
[解決済み】ジェネリックの<out T>と<T>の比較
-
[解決済み] 機能的デザインパターン【終了しました
-
[解決済み] なぜScalaのimmutable Setは型が共変しないのか?
-
[解決済み] Mapにkeyやvalueが存在するかどうかを確認するには?
-
[解決済み] Scalaのコレクションにenrich-my-libraryパターンを適用するにはどうしたらいいですか?
-
[解決済み] コレクションのGroovyマップメソッド
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Scalaです。リスト[Future]からFuture[List]への変換は、失敗したFutureを無視する。
-
[解決済み] scalaは推論される型の「許容される複雑さ」にどのような制限を設けているのでしょうか?
-
[解決済み] Scalaのアクター:受信と反応
-
[解決済み] build.sbtとbuild.scalaの違いは何ですか?
-
[解決済み] 末尾再帰関数が最適化されるためのScalaアノテーションは何ですか?
-
[解決済み] Scalaでサブアレイを取得する正しい方法は何ですか?
-
[解決済み] ScalaにおけるNull/Nothing/Unitの使用法
-
[解決済み] Abstract ClassとTraitの違い[重複]について
-
[解決済み] Scala における => と () => の意味 [重複].
-
[解決済み] ケースクラスのコンパニオンでapplyをオーバーライドする方法