当前位置: 首页 > 知识库问答 >
问题:

什么是TypeTag?我如何使用它?

上官斌
2023-03-14

我所知道的关于排字的只是它们以某种方式取代了舱单。互联网上的信息很少,不能给我提供一个很好的主题意识。

因此,如果有人分享一些关于排字的有用材料的链接,包括示例和流行的用例,我会很高兴的。也欢迎详细的解答和解释。

共有1个答案

章彬郁
2023-03-14

typetag解决了Scala的类型在运行时被擦除(类型擦除)的问题。如果我们想做

class Foo
class Bar extends Foo

def meth[A](xs: List[A]) = xs match {
  case _: List[String] => "list of strings"
  case _: List[Foo] => "list of foos"
}

我们会收到警告:

<console>:23: warning: non-variable type argument String in type pattern List[String]↩
is unchecked since it is eliminated by erasure
         case _: List[String] => "list of strings"
                 ^
<console>:24: warning: non-variable type argument Foo in type pattern List[Foo]↩
is unchecked since it is eliminated by erasure
         case _: List[Foo] => "list of foos"
                 ^

为了解决这个问题,Scala引入了清单。但是它们的问题是不能表示很多有用的类型,比如依赖路径的类型:

scala> class Foo{class Bar}
defined class Foo

scala> def m(f: Foo)(b: f.Bar)(implicit ev: Manifest[f.Bar]) = ev
warning: there were 2 deprecation warnings; re-run with -deprecation for details
m: (f: Foo)(b: f.Bar)(implicit ev: Manifest[f.Bar])Manifest[f.Bar]

scala> val f1 = new Foo;val b1 = new f1.Bar
f1: Foo = Foo@681e731c
b1: f1.Bar = Foo$Bar@271768ab

scala> val f2 = new Foo;val b2 = new f2.Bar
f2: Foo = Foo@3e50039c
b2: f2.Bar = Foo$Bar@771d16b9

scala> val ev1 = m(f1)(b1)
warning: there were 2 deprecation warnings; re-run with -deprecation for details
ev1: Manifest[f1.Bar] = Foo@681e731c.type#Foo$Bar

scala> val ev2 = m(f2)(b2)
warning: there were 2 deprecation warnings; re-run with -deprecation for details
ev2: Manifest[f2.Bar] = Foo@3e50039c.type#Foo$Bar

scala> ev1 == ev2 // they should be different, thus the result is wrong
res28: Boolean = true
scala> def m(f: Foo)(b: f.Bar)(implicit ev: TypeTag[f.Bar]) = ev
m: (f: Foo)(b: f.Bar)(implicit ev: reflect.runtime.universe.TypeTag[f.Bar])↩
reflect.runtime.universe.TypeTag[f.Bar]

scala> val ev1 = m(f1)(b1)
ev1: reflect.runtime.universe.TypeTag[f1.Bar] = TypeTag[f1.Bar]

scala> val ev2 = m(f2)(b2)
ev2: reflect.runtime.universe.TypeTag[f2.Bar] = TypeTag[f2.Bar]

scala> ev1 == ev2 // the result is correct, the type tags are different
res30: Boolean = false

scala> ev1.tpe =:= ev2.tpe // this result is correct, too
res31: Boolean = false
import scala.reflect.runtime.universe._

def meth[A : TypeTag](xs: List[A]) = typeOf[A] match {
  case t if t =:= typeOf[String] => "list of strings"
  case t if t <:< typeOf[Foo] => "list of foos"
}

scala> meth(List("string"))
res67: String = list of strings

scala> meth(List(new Bar))
res68: String = list of foos
scala> typeOf[List[java.lang.String]] =:= typeOf[List[Predef.String]]
res71: Boolean = true

scala> typeOf[List[java.lang.String]] == typeOf[List[Predef.String]]
res72: Boolean = false
  • scala.reflect.classtag
  • scala.reflect.api.typetags#typetag
  • scala.reflect.api.typetags#weaktypetag

classtag替代classmanifest,而typetag或多或少替代manifest

前者允许完全使用泛型数组

scala> import scala.reflect._
import scala.reflect._

scala> def createArr[A](seq: A*) = Array[A](seq: _*)
<console>:22: error: No ClassTag available for A
       def createArr[A](seq: A*) = Array[A](seq: _*)
                                           ^

scala> def createArr[A : ClassTag](seq: A*) = Array[A](seq: _*)
createArr: [A](seq: A*)(implicit evidence$1: scala.reflect.ClassTag[A])Array[A]

scala> createArr(1,2,3)
res78: Array[Int] = Array(1, 2, 3)

scala> createArr("a","b","c")
res79: Array[String] = Array(a, b, c)
scala> classTag[Int]
res99: scala.reflect.ClassTag[Int] = ClassTag[int]

scala> classTag[Int].runtimeClass
res100: Class[_] = int

scala> classTag[Int].newArray(3)
res101: Array[Int] = Array(0, 0, 0)

scala> classTag[List[Int]]
res104: scala.reflect.ClassTag[List[Int]] =↩
        ClassTag[class scala.collection.immutable.List]
scala> typeTag[List[Int]]
res105: reflect.runtime.universe.TypeTag[List[Int]] = TypeTag[scala.List[Int]]

scala> typeTag[List[Int]].tpe
res107: reflect.runtime.universe.Type = scala.List[Int]

scala> typeOf[List[Int]]
res108: reflect.runtime.universe.Type = scala.List[Int]

scala> res107 =:= res108
res109: Boolean = true
scala> def m[A : ClassTag : TypeTag] = (classTag[A], typeTag[A])
m: [A](implicit evidence$1: scala.reflect.ClassTag[A],↩
       implicit evidence$2: reflect.runtime.universe.TypeTag[A])↩
      (scala.reflect.ClassTag[A], reflect.runtime.universe.TypeTag[A])

scala> m[List[Int]]
res36: (scala.reflect.ClassTag[List[Int]],↩
        reflect.runtime.universe.TypeTag[List[Int]]) =↩
       (scala.collection.immutable.List,TypeTag[scala.List[Int]])

剩下的问题是WeakTypeTag是什么意思?简而言之,typetag表示具体类型(这意味着它只允许完全实例化的类型),而weaktypetag只允许任何类型。大多数时候,人们并不关心哪个是什么(这意味着应该使用typetag),但例如,当使用应该与泛型类型一起工作的宏时,就需要它们:

object Macro {
  import language.experimental.macros
  import scala.reflect.macros.Context

  def anymacro[A](expr: A): String = macro __anymacro[A]

  def __anymacro[A : c.WeakTypeTag](c: Context)(expr: c.Expr[A]): c.Expr[A] = {
    // to get a Type for A the c.WeakTypeTag context bound must be added
    val aType = implicitly[c.WeakTypeTag[A]].tpe
    ???
  }
}

如果将weaktypetag替换为typetag,则会引发错误:

<console>:17: error: macro implementation has wrong shape:
 required: (c: scala.reflect.macros.Context)(expr: c.Expr[A]): c.Expr[String]
 found   : (c: scala.reflect.macros.Context)(expr: c.Expr[A])(implicit evidence$1: c.TypeTag[A]): c.Expr[A]
macro implementations cannot have implicit parameters other than WeakTypeTag evidences
             def anymacro[A](expr: A): String = macro __anymacro[A]
                                                      ^

有关TypeTagweaktypetag之间差异的更详细说明,请参见以下问题:Scala宏:“不能从具有未解析类型参数的类型T创建TypeTag”

 类似资料:
  • 我得到以下错误: 它可能是另一种类型,而不是,但基本上模式是 所以 什么是未来 如何获得我想要的实际值 当我只有一个

  • 问题内容: 我一直在搜索,但仍然不确定“盐”是什么以及如何使用/实现它。对不起这个问题,我是自学php。 问题答案: 我绝对不是专家,但是真正简短的答案是“涂一行”文本意味着在其末尾添加一些额外的字符。您可以将“ salt”和“ abcdefg”加盐以获得“ saltabcdefg”。如果“盐”恰好是您想要使其更难猜测的密码,则这可能很有用。 通常,密码+盐会通过一些难以逆转的过程转换(“散列”)

  • 使用它来分析C或C++中的代码? 使用它来分析x86汇编程序中的代码?

  • 问题内容: 我正在阅读有关该功能的信息。问题是我仍然无法理解其用法。据我所知的唯一的事情是相同调用。 我不明白这本书何时提到你如何在运行时不知道其名称的情况下如何使用它来获取对函数的引用。总的来说,也许这是我在编程方面的菜鸟。谁能给这个问题一些启发?我什么时候以及如何使用它? 问题答案: 完全等同于。 有只有两个原因使用它: 你无法编写,因为你事先不知道想要哪个属性(它来自字符串)。对于元编程非常

  • 我正在研究一些对象的Flux,比如

  • 问题内容: 我一直在听到所有添加到JVM的新功能,这些功能之一是invokedynamic。我想知道它是什么,它如何使Java中的反射式编程更容易或更好? 问题答案: 这是一条新的JVM指令,它允许编译器生成代码,该代码以比以前更宽松的规范来调用方法-如果您知道“ 鸭子类型 ”是什么,invokedynamic基本上允许进行鸭子类型。作为Java程序员,您可以做的事情太多了。但是,如果您是工具创建