- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我对 TypeTags 的了解是,它们以某种方式取代了 Manifests。互联网上的信息很少,无法让我对这个主题有很好的了解。
因此,如果有人分享有关 TypeTags 的一些有用 Material (包括示例和流行用例)的链接,我会很高兴。也欢迎详细的解答和解释。
最佳答案
一个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"
^
解决这个问题Manifests被介绍给 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
因此,它们被替换为 TypeTags ,它们使用起来更加简单,并且很好地集成到了新的 Reflection API 中。有了它们,我们就可以优雅地解决上面关于路径依赖类型的问题:
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
后者检查结构相等性,这通常不是应该做的,因为它不关心诸如前缀之类的事情(如示例中所示)。
一个TypeTag
完全由编译器生成,这意味着编译器创建并填充 TypeTag
当调用一个期望这样的 TypeTag
的方法时。存在三种不同形式的标签:
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)
ClassTag
仅提供在运行时创建类型所需的信息(类型已删除):
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]
正如上面所看到的,他们不关心类型删除,因此如果想要“完整”类型 TypeTag
应该使用:
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
正如我们所见,方法 tpe
的TypeTag
结果完整Type
,这与 typeOf
时得到的结果相同叫做。当然,两者都可以使用,ClassTag
和TypeTag
:
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]
^
有关 TypeTag
之间差异的更详细说明和WeakTypeTag
看到这个问题:Scala Macros: “cannot create TypeTag from a type T having unresolved type parameters”
Scala 的官方文档网站还包含 guide for Reflection .
关于scala - 什么是 TypeTag 以及如何使用它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12218641/
一个简单的问题,如何从类名中获取 TypeTag? 所以基本上 TypeTag 相当于 Java 中的 Class.forName。 注意:Manifest 在这里不适合我,我需要一个 TypeTag
使用 Scala 2.10,我试图从字符串实例化一个类,我想获取它的类型标签。 例如 : scala> def printClassName[Y: TypeTag](x: Y) = { println
我对手动创建 TypeTag 感兴趣(从 2.10M5 开始): object X { import reflect.runtime.universe._ def tt[A : TypeTag
我正在尝试为内部类型获取 TypeTag 或 ClassTag 以向具有类型参数的方法提供 ClassTag。具体来说,我有 trait Baz trait Foo { type Bar weakT
在 REPL 中,我正在写出来自 Reflection - TypeTags and Manifests 的示例. 我对 WeakTypeTag 之间的区别感到困惑和 TypeTag . scala>
我对 TypeTags 的了解是,它们以某种方式取代了 Manifests。互联网上的信息很少,无法让我对这个主题有很好的了解。 因此,如果有人分享有关 TypeTags 的一些有用 Material
TypeTags 似乎只适用于被调用方法的参数中使用的类型参数,而不适用于返回类型: scala> :paste // Entering paste mode (ctrl-D to finish) i
说我有 trait Foo[T] { def bar: Bar[T] } 并希望在调用 Foo[Int] 时获取 bar 的返回类型(即本例中的 Bar[Int])来自 Foo[Int] 的类型标签和
我有一种方法可以探索不同类函数的不同参数值。以前,我做了一些非类型安全的运行时检查,其中,删除后,重要的是我使用的是 Function2 还是 Function3。我已经尝试使用 ClassTags/
我有 createOld我需要覆盖并且我无法更改它的方法。我想使用 TypeTag模式匹配 createNew 中提供的类型.目标是找出如何调用createNew来自 createOld .我目前的理
我们的库使用 TypeTags,但现在我们需要与另一个需要 Manifests 的库进行交互。有没有简单的方法可以从 TypeTag 创建 list ? 最佳答案 如果您在存在 TypeTag 时天真
以下代码未编译: override def read[T <: Product](collection : String): Dataset[T] = { val mongoDbRdd = Mon
我正在尝试修改 List.toString 的行为根据其类型参数。自 List无法扩展,被自定义类包裹 CList (可以使用隐式,但问题会保持不变?)。打印 CList 时出现问题的 CList s
简介 : ... TypeTag[T] encapsulates the runtime type representation of some compile-time type T. ... ..
我有一个简单的 Scala 程序来测试 Scala 推断类型类的能力: import scala.reflect.ClassTag object InferTypeTag { import org
下面是如何在运行时使用 Manifest 创建类型 T 的新实例: trait MyTrait class MyClass1(val name: String) extends MyTrait cla
这个问题已经有答案了: How to create a TypeTag manually? (5 个回答) 已关闭 3 年前。 在 Scala 反射中,通常可以使用 TypeCreator 从类型构造
我有一个多态方法,它将自定义案例类作为类型参数。现在,为了支持多个案例类(在配置文件中定义为字符串),我需要将字符串转换为案例类的 tagType。 为此,我使用 runtimeMirror 方法从
给定一个类: class MyClass[A, B[A] <: SomeClass[A]](...) { ... } 我想为 A 和 B[A] 添加类型标签。 但是, class MyClass[A:
我正在尝试将类型标记转换为维护/保留通常删除的类型参数的 java 类。有相当多的库受益于这些转换(例如 Jackson 和 Guice)。我目前正在尝试将基于 Manifest 的代码迁移到 Typ
我是一名优秀的程序员,十分优秀!