2

THE Javaプログラミング言語第4版によると。セクション 15.7.1「タイプ トークン」:

getClassはコンパイラによって特別な扱いを受けます。 getClassが静的型Tの参照で呼び出された場合、コンパイラは getClass の戻り値の型をClassとして扱います。したがって、これは機能します:

String str = "Hello";
Class<? extends String> c2 = str.getClass(); // compiler magic

クラス内のメソッドjavadoc でgetClassObject詳細を確認できます。

実際の結果の型 [of getClass()] はClass<? extends |X|>|X|getClass が呼び出された式の静的型の消去です。たとえば、次のコード フラグメントではキャストは必要ありません。

Number n = 0; 
Class<? extends Number> c = n.getClass();

それが Java とgetClass()class のメソッドですObject。Scala に注目すると、SLS 3.2.10 は次のように読み取ります。

存在型のプレースホルダー構文

構文:

WildcardType ::= ‘_’ TypeBounds

Scala は、存在型のプレースホルダー構文をサポートしています。ワイルドカード型の形式は_ >: L <: U ... ワイルドカード型は、存在量化された型変数の短縮形であり、存在量化は暗黙的です。

... T = pc[targs, T, targs']をパラメーター化された型にします。ここで、targstargs'は空で、Tはワイルドカード型_ >: L <: Uです。その場合、 Tは存在型と同等です

pc[targs, t , targs ] forSome { type t >: L <: U }

ここで、tは新しい型変数です。

私が観察している動作がそのステートメントと矛盾しているように見えるため、上記の「T は実存型と同等です...」と強調しました。

私がしたこと

Scala repl では、SLS 3.2.10 のワイルドカード構文を試します。

scala> val c: Class[_ >: scala.Nothing <: String] = "foo".getClass
c: Class[_ <: String] = class java.lang.String

それは私が期待するように動作します。しかし、SLS 3.2.10 で主張されている「ワイルドカード型は、存在量化された型変数の省略形である」という同等性に依存すると、予期しないエラーが発生します。

scala> val c: Class[t forSome { type t >: scala.Nothing <: String }] = "foo".getClass
<console>:7: error: type mismatch;
 found   : java.lang.Class[?0] where type ?0 <: java.lang.String
 required: Class[t forSome { type t <: String }]
Note: ?0 <: t forSome { type t <: String }, but Java-defined class Class is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: t forSome { type t <: String }`. (SLS 3.2.10)
       val c: Class[t forSome { type t >: scala.Nothing <: String }] = "foo".getClass
                                                                         ^

エラー メッセージは、再帰的に SLS 3.2.10 に戻っているように見えます。これは、ワイルドカード構文と明示的な存在数量化の両方を使用することを示唆しています。意味がわかりません。Objectいずれにせよ、上記で引用した javadoc の例を使用して、同じ二分法を観察します。

scala> val n: Number = 0
n: java.lang.Number = 0

作品:

scala> val c: Class[_ >: scala.Nothing <: Number] = n.getClass
c: Class[_ <: java.lang.Number] = class java.lang.Integer

動作しません:

scala> val c: Class[t forSome { type t >: scala.Nothing <: Number }] = n.getClass
<console>:8: error: type mismatch;
 found   : java.lang.Class[?0] where type ?0 <: java.lang.Number
 required: Class[t forSome { type t <: java.lang.Number }]
Note: ?0 <: t forSome { type t <: java.lang.Number }, but Java-defined class Class is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: t forSome { type t <: java.lang.Number }`. (SLS 3.2.10)
       val c: Class[t forSome { type t >: scala.Nothing <: Number }] = n.getClass

質問

主に

特定のワイルドカード型が特定の存在型と「同等」である場合、それは一方を他方に置き換えることができるということですか? それが等価性の意味ではないでしょうか。SLS 3.2.10 で使用されている「同等性」の意味を正しく理解していると仮定すると、SLS 3.2.10 で規定されている規則に従って同等の置換を行う試みに誤りがありますか? SLS 3.2.10 と一致する存在型を含む、上で引用した 2 つのステートメントを処理する repl の失敗は、どのようにして失敗するステートメントが成功するワイルドカード型を使用するステートメントと同等になるのでしょうか?

さらに

問題のエラーメッセージの必須行と見つかった行で指定されたタイプの違いは何ですか? つまり、これはどうですか:

java.lang.Class[?0] where type ?0 <: java.lang.String

と違う

Class[t forSome { type t <: String }]

そして、最初のクエスチョン マークは何ですか? 明らかに?0何か意味があって、型変数のようですが、そんなクエスチョンマークを使うのはScalaじゃないですよね?そのエラーメッセージを理解できるように、それは何語で、どこに指定されていますか?

4

2 に答える 2