具有网站上方法类型参数

时间:2016-06-29 06:10:13

标签: scala

以下示例:

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]更改为上限时 - 正如预期的那样,代码无法编译

有人能否了解这里发生的事情? 谢谢!

2 个答案:

答案 0 :(得分:3)

在您的示例中编译约束B >: A的原因是编译器尝试查找满足约束的最具体类型。由于Int是您的下限,而StringInt都共享超类型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]]会得到相同的结果。)