我所知道的TypeTags就是他们以某种方式取代了Manifest.互联网上的信息很少,并没有让我对这个主题有很好的认识.
所以,如果有人在TypeTag上分享了一些有用的资料,包括例子和流行的用例,我会很高兴.我们也欢迎详细的解答和解释.
最好通过一个例子来解释这个问题:
在Java中,对于JPA EntityManager,我可以执行以下操作(Account是我的Entity类):
Account result = manager.find(Account.class, primaryKey);
Run Code Online (Sandbox Code Playgroud)
在Scala中,我天真的尝试是:
val result = manager.find(Account.class, primaryKey)
Run Code Online (Sandbox Code Playgroud)
但是当我尝试Account.class在Scala中使用时,似乎不喜欢这个.如何在Scala中为Account类指定java.lang.Class对象?
我最近开始学习Scala并且很失望(但并不感到惊讶)他们的泛型也是通过类型擦除来实现的.
我的问题是,Scala是否有可能使用具体的泛型,或者JVM是否需要以某种方式进行更改?如果确实需要更改JVM,究竟需要更改什么?
我们假设我们有一个泛型类Container:
case class Container[+A](value: A)
Run Code Online (Sandbox Code Playgroud)
然后,我们希望模式匹配一个Container有Double和Container的Any:
val double = Container(3.3)
var container: Container[Any] = double
Run Code Online (Sandbox Code Playgroud)
为此,我们通常会写:
container match {
case c: Container[String] => println(c.value.toUpperCase)
case c: Container[Double] => println(math.sqrt(c.value))
case _ => println("_")
}
Run Code Online (Sandbox Code Playgroud)
但是,编译器会给出两个警告,前两个案例各一个.例如,第一个警告说:"类型模式容器[String]中的非变量类型参数字符串未被选中,因为它被擦除".由于擦除,在运行期间不可能区分不同类型的容器并且第一个捕获物将匹配.因此,类型的容器Container[Double]将与捕获Container[String]对象的第一个案例匹配,因此toUpperCase将在a上调用方法,Double并且java.lang.ClassCastException将抛出a.
如何匹配Container特定类型的参数化?
我有兴趣手动创建一个TypeTag(从2.10M5开始):
object X {
import reflect.runtime.universe._
def tt[A : TypeTag](a: A) = typeTag[A] // how to do this manually?
val t = tt(List("")(_))
}
Run Code Online (Sandbox Code Playgroud)
scalac -Xprint:typer <file>.scala 结果是
package <empty> {
object X extends scala.AnyRef {
def <init>(): X.type = {
X.super.<init>();
()
};
import scala.reflect.runtime.`package`.universe._;
def tt[A >: Nothing <: Any](a: A)(implicit evidence$1: reflect.runtime.universe.TypeTag[A]): reflect.runtime.universe.TypeTag[A] = scala.reflect.runtime.`package`.universe.typeTag[A](evidence$1);
private[this] val t: reflect.runtime.universe.TypeTag[Int => String] = X.this.tt[Int => String](((x$1: Int) => immutable.this.List.apply[String]("").apply(x$1)))({
val $u: reflect.runtime.universe.type = scala.this.reflect.runtime.`package`.universe;
val $m: $u.Mirror = …Run Code Online (Sandbox Code Playgroud) 我有两个函数(不是这些函数自原版以来都已编辑过 - 下面的一些答案是对原始函数的响应,它们返回了一系列的()):
def foo1[A](ls: Iterable[A]) : Iterator[A] =
for (List(a, b) <- ls sliding 2) yield a
def foo2[A](ls: Iterable[A]) : Iterator[A] =
for (a::b::Nil <- ls sliding 2) yield a
Run Code Online (Sandbox Code Playgroud)
我天真地认为是相同的.但是斯卡拉只对第一个有所减弱:
warning: non variable type-argument A in type pattern List[A]
is unchecked since it is eliminated by erasure
Run Code Online (Sandbox Code Playgroud)
我想我理解为什么它会给第一个错误:Scala认为我正在尝试使用该类型作为模式的条件,即List[B](_, _)如果B不从A继承,则匹配应该失败,除了这可以之所以发生,是因为在这两种情况下都会删除类型.
所以有两个问题:
1)为什么第二个不给出同样的警告?
2)是否有可能说服Scala在编译时实际知道该类型,因此不可能无法匹配?
编辑:我认为这回答了我的第一个问题.但我仍然对第二个感到好奇.
编辑:agilesteel在评论中提到
for (List(a, b) <- List(1,2,3,4) sliding 2) yield ()
Run Code Online (Sandbox Code Playgroud)
没有警告.这有什么不同foo1(不应该[Int]参数被删除与[A]参数相同)?
有一个泛型类:
class Action[T]
Run Code Online (Sandbox Code Playgroud)
创建它的一些实例,放入一个列表:
val list = List(new Action[String], new Action[Int])
Run Code Online (Sandbox Code Playgroud)
迭代它,以及如何获得实例的实际类型?
list foreach { action =>
// how do I know the action is for a String or an Int?
}
Run Code Online (Sandbox Code Playgroud) Manifest由于JVM缺乏具体的泛型,Scala 是一种解决某些类型擦除问题的方法.
在其他几个问题中讨论了它们; 这里有几个:
其中一条评论提到"此功能是实验性的,有些情况下它不起作用.不过,它还有很长的路要走."(Daniel Sobral)
Manifest方法崩溃的原因是什么?为什么?
给定一个类型声明,我能够解析类型参数.
scala> reflect.runtime.universe.typeOf[List[Int]] match {case x:TypeRef => x.args}
res10: List[reflect.runtime.universe.Type] = List(Int)
Run Code Online (Sandbox Code Playgroud)
对于运行时值,相同的方法不起作用.
scala> reflect.runtime.currentMirror.reflect(List(42)).symbol.toType match {case x:TypeRef => x.args}
res11: List[reflect.runtime.universe.Type] = List(B)
Run Code Online (Sandbox Code Playgroud)
有没有办法克服反射值的类型擦除?
Haskell相当于下面的代码会产生正确的答案吗?
可以修复此Scala代码以生成正确的答案吗?如果有,怎么样?
object TypeErasurePatternMatchQuestion extends App {
val li=List(1,2,3)
val ls=List("1","2","3")
val si=Set(1,2,3)
val ss=Set("1","2","3")
def whatIsIt(o:Any)=o match{
case o:List[Int] => "List[Int]"
case o:List[String] => "List[String]"
case o:Set[Int] => "Set[Int]"
case o:Set[String] => "Set[String]"
}
println(whatIsIt(li))
println(whatIsIt(ls))
println(whatIsIt(si))
println(whatIsIt(ss))
}
Run Code Online (Sandbox Code Playgroud)
打印:
List[Int]
List[Int]
Set[Int]
Set[Int]
Run Code Online (Sandbox Code Playgroud)
但我希望它能打印出来:
List[Int]
List[String]
Set[Int]
Set[String]
Run Code Online (Sandbox Code Playgroud) scala ×10
type-erasure ×4
generics ×3
java ×2
reification ×2
scala-2.10 ×2
class ×1
erasure ×1
haskell ×1
jvm ×1
manifest ×1
reflection ×1
types ×1