以下示例:
class Test[A] {
def print[B >: A](x : B): Unit = {
println(x.isInstanceOf[A])
println(x.isInstanceOf[B])
}
}
val test = new Test[Int]
test.print("string")
返回true true
(这意味着A,B是字符串的类型)
当[B <: A]
更改为上限时 - 正如预期的那样,代码无法编译
有人能否了解这里发生的事情? 谢谢!
答案 0 :(得分:3)
在您的示例中编译约束B >: A
的原因是编译器尝试查找满足约束的最具体类型。由于Int
是您的下限,而String
和Int
都共享超类型Any
,编译器允许此示例进行编译。< / p>
您必须记住的一件事是Scala在JVM上运行(好吧,至少是最常见的发行版)。这意味着我们为通用类型提供了 type erasure 。
如果我们编译你的例子并查看post擦除阶段,我们会看到:
class Test extends Object {
def print(x: Object): Unit = {
scala.this.Predef.println(scala.Boolean.box(x.$isInstanceOf[Object]()));
scala.this.Predef.println(scala.Boolean.box(x.$isInstanceOf[Object]()))
};
}
如您所见,由于类型擦除,我们实际上将x
两次与Object
进行了比较,这就是您看到true
打印两次的原因。
如果要检查类型是否相等,则需要提供TypeTag
的隐式证据。 TypeTag
在运行时提供类型信息。如果提供,我们可以使用typeOf
和=:=
来检查特定类型的相等性。我们要么通过上下文边界要求TypeTag
,要么通过隐式参数明确要求(对于这个例子,我将使用前者):
scala> :pa
// Entering paste mode (ctrl-D to finish)
import scala.reflect.runtime.universe._
class Test[A: TypeTag] {
def print[B: TypeTag](x: B): Unit = {
println(typeOf[B] =:= typeOf[A])
println(typeOf[B] =:= typeOf[B])
}
}
// Exiting paste mode, now interpreting.
import scala.reflect.runtime.universe._
defined class Test
scala> val t = new Test[Int]
t: Test[Int] = Test@7276c8cd
scala> t.print("s")
false
true
答案 1 :(得分:0)
如果你想做同等级的x.isInstanceOf[A]
,scala.reflect.ClassTag
可能比TypeTag
更合适:
import scala.reflect.{ClassTag, classTag}
class Test[A: ClassTag] {
def print[B >: A : ClassTag](x : B): Unit = {
println(x match { case _: A => true; case _ => false })
// or println(classTag[A].runtimeClass.isInstance(x))
println(x match { case _: B => true; case _ => false })
}
}
val test = new Test[Int]
test.print("string")
与isInstanceOf
类似,上面的内容适用于x
的实际值,而不是静态类型。您可以通过调用
val test = new Test[Some[Int]]
val x: Option[Int] = Some(1)
val y: Option[Int] = None
test.print(x)
test.print(y)
用这个和另一个答案。 (但请注意,ClassTag
不会处理类型参数:new Test[Some[String]]
会得到相同的结果。)