Scala 如何比较两个对象并要求它们具有相同的类型?

Scala 如何比较两个对象并要求它们具有相同的类型?,scala,comparison,Scala,Comparison,我认为比较两个不同类型的物体是一个很常见的错误 case class User(name:Option[String]) val user = User(Some("Freewind")) if(user.name == "Freewind") { // never be true!!! ... } 如果有任何方法可以比较两个对象,同时要求它们具有相同的类型?因此,严格来说,“变量类型”始终存在,并且可以作为类型参数传递。例如: val x = 5 def f[T](v: T) =

我认为比较两个不同类型的物体是一个很常见的错误

case class User(name:Option[String])

val user = User(Some("Freewind"))

if(user.name == "Freewind") { // never be true!!!
    ...
}

如果有任何方法可以比较两个对象,同时要求它们具有相同的类型?

因此,严格来说,“变量类型”始终存在,并且可以作为类型参数传递。例如:

val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x
val x: Any = 5
import scala.reflect.ClassTag
def f[T](v: T)(implicit ev: ClassTag[T]) = ev.toString
f(x) // returns the string "Any"
但取决于你想做什么,这对你没有帮助。例如,您可能不想知道变量的类型,但想知道值的类型是否是某个特定类型,例如:

val x: Any = 5
def f[T](v: T) = v match {
  case _: Int    => "Int"
  case _: String => "String"
  case _         => "Unknown"
}
f(x)
在这里,变量的类型是什么都不重要。重要的是,检查的是5的类型,即值。事实上,T是无用的——您还不如将它写成def(v:Any)。此外,它使用ClassTag或value的类(如下所述),并且无法检查类型的类型参数:您可以检查某个对象是否是列表[u](某个对象的列表),但不能检查它是否是列表[Int]或列表[String]

另一种可能是您希望具体化变量的类型。也就是说,您希望将类型转换为一个值,这样您就可以存储它,传递它,等等。这涉及到反射,您将使用ClassTag或TypeTag。例如:

val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x
val x: Any = 5
import scala.reflect.ClassTag
def f[T](v: T)(implicit ev: ClassTag[T]) = ev.toString
f(x) // returns the string "Any"
ClassTag还允许您使用在match上收到的类型参数。这行不通:

def f[A, B](a: A, b: B) = a match {
  case _: B => "A is a B"
  case _ => "A is not a B"
}
但这将:

val x: Any = 5
val y = 5
import scala.reflect.ClassTag
def f[A, B: ClassTag](a: A, b: B) = a match {
  case _: B => "A is a B"
  case _ => "A is not a B"
}
f(x, y) // A (Any) is not a B (Int)
f(y, x) // A (Int) is a B (Any)
这里我使用的是上下文边界语法,B:ClassTag,它的工作原理与前面的ClassTag示例中的隐式参数类似,但是使用了一个匿名变量

还可以从值的类中获取类标记,如下所示:

val x: Any = 5
val y = 5
import scala.reflect.ClassTag
def f(a: Any, b: Any) = {
  val B = ClassTag(b.getClass)
  ClassTag(a.getClass) match {
    case B => "a is the same class as b"
    case _ => "a is not the same class as b"
  }
}
f(x, y) == f(y, x) // true, a is the same class as b
ClassTag的局限性在于它只覆盖基类,而不覆盖其类型参数。也就是说,List[Int]和List[String]的类标记是相同的List。如果需要类型参数,则必须使用TypeTag。然而,由于JVM的擦除,不能从值中获取TypeTag,也不能在模式匹配中使用它

使用TypeTag的示例可能会变得非常复杂——即使不比较两个类型标记也不是很简单,如下所示:

import scala.reflect.runtime.universe.TypeTag
def f[A, B](a: A, b: B)(implicit evA: TypeTag[A], evB: TypeTag[B]) = evA == evB
type X = Int
val x: X = 5
val y = 5
f(x, y) // false, X is not the same type as Int
当然,有一些方法可以让这种比较返回真值,但需要几章书才能真正涵盖TypeTag,所以我就到此为止

最后,也许您根本不关心变量的类型。也许你只是想知道一个值的类别,在这种情况下答案很简单:

val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it

不过,最好更具体地说明您想要完成的任务,这样答案就更切题了。

实际上,您不能使用
=
操作符来实现这一点,因为它就像Java
对象.equals
方法一样。 实际上,通过构造新操作符
===
解决了这个问题。
请看:

Scalaz有一个
Equal
type类()。我还注意到,有时候scalac在比较不相关的类型时会发出警告,但似乎是这样。

有一种方法可以做到这一点,但几乎总是一个错误。@n.m.你能详细说明什么是错误以及为什么吗?嗯,也许你应该先解释一下你心目中的“要求”是什么。是否希望静态类型相同,并在编译时强制执行?还是在运行时检查相同的动态类型?谢谢,我是说编译时的“静态类型”答案上的链接断开了