【问题标题】:Method to check reference equality for Any type检查任何类型的引用相等性的方法
【发布时间】:2011-11-11 08:18:30
【问题描述】:

我正在尝试创建一个可以匹配任何类型(包括原语)的引用相等性的方法。如何最好地做到这一点?

eq 仅在 AnyRef 上定义。如果我们尝试

def refEquals[A <% AnyRef, B <% AnyRef](a: A, b: B) = a eq b

然后在运行refEquals(1,2) 时,我们发现Predef 中有隐式方法,包括int2IntegerConflict 来破坏此类转换。

我试过这个:

def refEquals(a: Any, b: Any) = a match {
  case x: AnyRef => b match {
    case y: AnyRef => x eq y
    case _ => false
  }
  case x: Any => b match {
    case y: AnyRef => false
    case y: Any => x == y
  }
}

但这不起作用(refEquals(1.0, 1.0) 给出false),原因由 Rex Kerr 给出:Strange pattern matching behaviour with AnyRef

那么我们如何实现这样的方法呢?

edit:应该说“引用类型的引用相等,或原始类型的值相等”。

编辑:这是使用 Rex 回答中的想法的方法,适用于需要此内容且不喜欢打字的任何人:

def refEquals(a: Any, b: Any) = a match {
  case x: Boolean if b.isInstanceOf[Boolean] => x == b
  case x: Byte    if b.isInstanceOf[Byte]    => x == b
  case x: Short   if b.isInstanceOf[Short]   => x == b
  case x: Char    if b.isInstanceOf[Char]    => x == b
  case x: Int     if b.isInstanceOf[Int]     => x == b
  case x: Float   if b.isInstanceOf[Float]   => x == b
  case x: Double  if b.isInstanceOf[Double]  => x == b
  case x: Long    if b.isInstanceOf[Long]    => x == b
  case _ => a.asInstanceOf[AnyRef] eq b.asInstanceOf[AnyRef]
}

【问题讨论】:

    标签: scala equals


    【解决方案1】:

    原始类型的引用相等是未定义的,因为它们不是引用。在这种情况下,唯一的平等概念是价值平等。

    但是,如果您希望代码同时使用原始类型和引用类型,则可以使用“==”并确保传递不重新定义“等于”的对象,或者定义自己的相等对象并传递它周围。您可能可以使用 'scala.math.Equiv[T]'。

    def myRefEquals[A](x: A, y: A)(implicit eq: Equiv[A]) {
      eq.equiv(x, y)
    }
    
    implicit def anyRefHasRefEquality[A <: AnyRef] = new Equiv[A] {
      def equiv(x: A, y: A) = x eq y
    }
    
    implicit def anyValHasUserEquality[A <: AnyVal] = new Equiv[A] {
      def equiv(x: A, y: A) = x == y
    }
    
    println(myRefEquals(Some(1), Some(1)))
    

    这假设您希望两个对象具有相同的类型。

    【讨论】:

    • 有没有办法检查两个基元是否相同?目前这会为myRefEquals(1, 1.0) 返回true
    • @LuigiPlinge 它们由 time 方法看到的相同类型,因为编译器插入了从 IntDouble 的隐式转换。避免它的唯一方法(我认为)是采用(x: Any, y: Any)的方法。
    【解决方案2】:

    你先捕捉到所有的原语,然后通过 eq:

    def refEquals(a: Any, b: Any) = a match {
      case x: Boolean => b match {
        case y: Boolean => x==y
        case _ => false
      }
      case x: Byte =>
      ...
      case _ => a.asInstanceOf[AnyRef] eq b.asInstanceOf[AnyRef]
    }
    

    【讨论】:

    • 为什么这不是 Any#eq 方法的默认值?
    • @ManuelSchmidt - 可能只是为了避免意外的计算开销。 eq 检查速度很快。判断你是八个原语中的哪一个要慢得多。不过,内置一些东西会很好。
    猜你喜欢
    • 1970-01-01
    • 2020-03-20
    • 2017-01-20
    • 2012-02-23
    • 2016-12-24
    • 2011-04-15
    • 1970-01-01
    • 1970-01-01
    • 2013-05-31
    相关资源
    最近更新 更多