为什么在REPL中没有观察到通配符和存在类型之间的指定等价

Ada*_*ler 2 java types scala existential-type type-bounds

根据THE Java Programming Language 4th ed.第15.7.1节"类型代币":

getClass接受编译器的特殊处理:如果在具有静态类型 T的引用上调用 getClass,则编译器将 getClass的返回类型视为 Class.这样可行:

String str = "Hello";
Class<? extends String> c2 = str.getClass(); // compiler magic
Run Code Online (Sandbox Code Playgroud)

类中方法javadoc提供了getClassObject更多细节:

[实际结果类型getClass()]是Class<? extends |X|>其中|X|是静态类型在其上的getClass称为表达的擦除.例如,此代码片段中不需要强制转换:

Number n = 0; 
Class<? extends Number> c = n.getClass();
Run Code Online (Sandbox Code Playgroud)

这是Java和getClass()类的方法Object.将注意力转向Scala,SLS 3.2.10读取,

存在类型的占位符语法

句法:

WildcardType ::= ‘_’ TypeBounds
Run Code Online (Sandbox Code Playgroud)

Scala支持存在类型的占位符语法.甲通配符类型的形式是_>:L <:U ...一个通配符类型是用于存在性量化型变量,其中存在量化是隐式的简写.

...设T = pc [targs,T,targs']是参数化类型,其中targs,targs'可能为空,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
Run Code Online (Sandbox Code Playgroud)

这符合我的预期.但是,如果我依赖于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
                                                                         ^
Run Code Online (Sandbox Code Playgroud)

错误消息似乎正在引导我递归回到SLS 3.2.10,建议我同时使用通配符语法和快速存在量化.我不明白这意味着什么.无论如何,我使用Object上面引用的javadoc中的示例观察到相同的二分法:

scala> val n: Number = 0
n: java.lang.Number = 0
Run Code Online (Sandbox Code Playgroud)

作品:

scala> val c: Class[_ >: scala.Nothing <: Number] = n.getClass
c: Class[_ <: java.lang.Number] = class java.lang.Integer
Run Code Online (Sandbox Code Playgroud)

不起作用:

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
Run Code Online (Sandbox Code Playgroud)

问题

主要

如果特定的通配符类型与特定的存在类型"等效",那是否意味着可以替换另一个?这不是等价的意思吗?假设我正确理解SLS 3.2.10中使用的"等价"含义,我是否在根据SLS 3.2.10中规定的规则进行等效替换时出错?如何处理我在上面引用的包含与SLS 3.2.10一致的存在类型的两个语句的失败,根据这些语句,失败的语句等同于使用成功的通配符类型的语句?

另外

有问题的错误消息的必需行和找到行中指定的类型之间有什么区别?也就是说,这是怎么回事:

java.lang.Class[?0] where type ?0 <: java.lang.String
Run Code Online (Sandbox Code Playgroud)

不同于

Class[t forSome { type t <: String }]
Run Code Online (Sandbox Code Playgroud)

第一个问题是什么?显然?0意味着什么,它似乎是一个类型变量,但使用像这样的问号不是Scala,是吗?它是什么语言,它在哪里指定,所以我能理解错误信息?

Rég*_*les 5

再看一下你引用的规范部分:

设T = pc [targs,T,targs']是参数化类型,其中targs,targs'可以为空,T是通配符类型_>:L <:U.那么T相当于存在类型pc [targs,t,targs] forSome {type t>:L <:U}其中t是一些新的类型变量.

特别要注意它的说法p.c[targs, t , targs ] forSome { type t >: L <: U }不是 p.c[targs, t forSome { type t >: L <: U } , targs ].这两种类型是不同的.

回到Class它的上下文意味着Class[_ >: scala.Nothing <: String]相当于Class[t] forSome { type t >: scala.Nothing <: String},而不是 Class[t forSome { type t >: scala.Nothing <: String }].

果然,如果你在REPL中输入以下内容,它会很好:

val c: Class[t] forSome { type t >: scala.Nothing <: String } = "foo".getClass
Run Code Online (Sandbox Code Playgroud)