scala 类型擦除 - 匹配大小写 class
scala type erasure - matching case class
我正在阅读有关类型擦除的内容,here
case class Thing[T](value: T)
def processThing(thing: Thing[_]) = {
thing match {
case Thing(value: Int) => "Thing of int" //isn't thing Thing[_] anymore?
case Thing(value: String) => "Thing of string" //isn't thing Thing[_] anymore?
case Thing(value: Seq[Int]) => "Thing of Seq[Int]" //value=Seq[_] really
case Thing(value: Seq[String]) => "Thing of Seq[String]" //value=Seq[_] really
case _ => "Thing of something else"
}
}
println(processThing(Thing(Seq(1,2,3)))) //type erased, I get it
println(processThing(Thing(Seq("hello", "yo")))) //type erased, I get it
println(processThing(Thing(1))) //why is this working?
println(processThing(Thing("hello"))) //why is this working?
我明白为什么 Seq[Int] 和 Seq[String] 没有被正确识别,在运行时两者都被视为 Seq[Object]。
但是,我不明白为什么前两个示例有效:
为什么 Thing[Int] 和 Thing[String] 都是 Thing[T]
没有与 Seq[T] 相同的问题...
为什么 Thing[Seq[T]] 被类型擦除
但是 Thing[T] (T=Int, String) 不是?
谁能解释一下这是怎么回事?谢谢
考虑以下 Java 代码:
class Foo {
<T> void bar(T whatIsIt) {
System.out.println("It is a: " + whatIsIt.getClass().getName());
}
public static void main() {
Foo f = new Foo();
f.bar(123);
f.bar("Hello world");
f.bar(f);
f.bar(new ArrayList<String>());
}
}
运行时只有一种方法Foo#bar(Object)
。但是作为 whatIsIt
传入的对象仍然有一个指向任何 class 它 实际上 的指针。
Scala 可以访问与 Java 相同的元数据。因此,当它为 processThing
构建字节码时,它可以插入 value instanceOf Integer
- 这就是它所做的:
scala> :javap processThing
// ... snip ...
public java.lang.String processThing($line3.$read$$iw$Thing<?>);
descriptor: (L$line3/$read$$iw$Thing;)Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=8, args_size=2
0: aload_1
1: astore_3
2: aload_3
3: ifnull 29
6: aload_3
7: invokevirtual #37 // Method $line3/$read$$iw$Thing.value:()Ljava/lang/Object;
10: astore 4
12: aload 4
14: instanceof #39 // class java/lang/Integer
17: ifeq 26
20: ldc #41 // String Thing of int
// ... snip ...
你是对的,在运行时 Thing(1)
和 Thing("Hello")
将擦除到相同的 class Thing
.
因此,如果您这样做:
thing match {
case _: Thing[Int] => foo
case _: Thing[String] => bar
}
您会看到预期的行为。
但是,您的模式匹配正在做一些不同的事情,它提取 thing
中的值,然后对其执行 class 检查。
值的class信息是自己保留的,所以你可以区分Int
、String
和Seq
,但看不到类型是什么Seq
的参数
但是,您可以尝试检查 Seq
的第一个元素......但这仍然不够,因为第一个元素可能是 Dog
而第二个元素可能是 Cat
因为它是 Seq[Animal]
并且该检查比之前的检查更不安全,因为 Seq
可能是空的。
我正在阅读有关类型擦除的内容,here
case class Thing[T](value: T)
def processThing(thing: Thing[_]) = {
thing match {
case Thing(value: Int) => "Thing of int" //isn't thing Thing[_] anymore?
case Thing(value: String) => "Thing of string" //isn't thing Thing[_] anymore?
case Thing(value: Seq[Int]) => "Thing of Seq[Int]" //value=Seq[_] really
case Thing(value: Seq[String]) => "Thing of Seq[String]" //value=Seq[_] really
case _ => "Thing of something else"
}
}
println(processThing(Thing(Seq(1,2,3)))) //type erased, I get it
println(processThing(Thing(Seq("hello", "yo")))) //type erased, I get it
println(processThing(Thing(1))) //why is this working?
println(processThing(Thing("hello"))) //why is this working?
我明白为什么 Seq[Int] 和 Seq[String] 没有被正确识别,在运行时两者都被视为 Seq[Object]。
但是,我不明白为什么前两个示例有效: 为什么 Thing[Int] 和 Thing[String] 都是 Thing[T] 没有与 Seq[T] 相同的问题...
为什么 Thing[Seq[T]] 被类型擦除 但是 Thing[T] (T=Int, String) 不是?
谁能解释一下这是怎么回事?谢谢
考虑以下 Java 代码:
class Foo {
<T> void bar(T whatIsIt) {
System.out.println("It is a: " + whatIsIt.getClass().getName());
}
public static void main() {
Foo f = new Foo();
f.bar(123);
f.bar("Hello world");
f.bar(f);
f.bar(new ArrayList<String>());
}
}
运行时只有一种方法Foo#bar(Object)
。但是作为 whatIsIt
传入的对象仍然有一个指向任何 class 它 实际上 的指针。
Scala 可以访问与 Java 相同的元数据。因此,当它为 processThing
构建字节码时,它可以插入 value instanceOf Integer
- 这就是它所做的:
scala> :javap processThing
// ... snip ...
public java.lang.String processThing($line3.$read$$iw$Thing<?>);
descriptor: (L$line3/$read$$iw$Thing;)Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=8, args_size=2
0: aload_1
1: astore_3
2: aload_3
3: ifnull 29
6: aload_3
7: invokevirtual #37 // Method $line3/$read$$iw$Thing.value:()Ljava/lang/Object;
10: astore 4
12: aload 4
14: instanceof #39 // class java/lang/Integer
17: ifeq 26
20: ldc #41 // String Thing of int
// ... snip ...
你是对的,在运行时 Thing(1)
和 Thing("Hello")
将擦除到相同的 class Thing
.
因此,如果您这样做:
thing match {
case _: Thing[Int] => foo
case _: Thing[String] => bar
}
您会看到预期的行为。
但是,您的模式匹配正在做一些不同的事情,它提取 thing
中的值,然后对其执行 class 检查。
值的class信息是自己保留的,所以你可以区分Int
、String
和Seq
,但看不到类型是什么Seq
的参数
但是,您可以尝试检查 Seq
的第一个元素......但这仍然不够,因为第一个元素可能是 Dog
而第二个元素可能是 Cat
因为它是 Seq[Animal]
并且该检查比之前的检查更不安全,因为 Seq
可能是空的。