转换java.util.IdentityHashMap中以scala.immutable.Map(C

2019-10-29 04:15发布

什么是一个转换的最简单方法java.util.IdentityHashMap[A,B]到的亚型scala.immutable.Map[A,B] 我需要保持键分开,除非他们是eq

以下是我试过到目前为止:

scala> case class Example()
scala> val m = new java.util.IdentityHashMap[Example, String]()
scala> m.put(Example(), "first!")
scala> m.put(Example(), "second!")
scala> m.asScala // got a mutable Scala equivalent OK
res14: scala.collection.mutable.Map[Example,String] = Map(Example() -> first!, Example() -> second!)
scala> m.asScala.toMap // doesn't work, since toMap() removes duplicate keys (testing with ==)
res15: scala.collection.immutable.Map[Example,String] = Map(Example() -> second!)

Answer 1:

这里有一个简单的实现Scala的身份地图。 在使用,它应该是类似于标准不变的地图。

实例:

val im = IdentityMap(
  new String("stuff") -> 5,
  new String("stuff") -> 10)

println(im) // IdentityMap(stuff -> 5, stuff -> 10)

您的情况:

import scala.collection.JavaConverters._
import java.{util => ju}

val javaIdentityMap: ju.IdentityHashMap = ???
val scalaIdentityMap = IdentityMap.empty[String,Int] ++ javaIdentityMap.asScala

实现本身(由于性能原因,可能有一些需要重写更多的方法):

import scala.collection.generic.ImmutableMapFactory
import scala.collection.immutable.MapLike

import IdentityMap.{Wrapper, wrap}

class IdentityMap[A, +B] private(underlying: Map[Wrapper[A], B])
  extends Map[A, B] with MapLike[A, B, IdentityMap[A, B]] {

  def +[B1 >: B](kv: (A, B1)) =
    new IdentityMap(underlying + ((wrap(kv._1), kv._2)))

  def -(key: A) =
    new IdentityMap(underlying - wrap(key))

  def iterator =
    underlying.iterator.map {
      case (kw, v) => (kw.value, v)
    }

  def get(key: A) =
    underlying.get(wrap(key))

  override def size: Int =
    underlying.size

  override def empty =
    new IdentityMap(underlying.empty)

  override def stringPrefix =
    "IdentityMap"
}

object IdentityMap extends ImmutableMapFactory[IdentityMap] {
  def empty[A, B] =
    new IdentityMap(Map.empty)

  private class Wrapper[A](val value: A) {
    override def toString: String =
      value.toString

    override def equals(other: Any) = other match {
      case otherWrapper: Wrapper[_] =>
        value.asInstanceOf[AnyRef] eq otherWrapper.value.asInstanceOf[AnyRef]
      case _ => false
    }

    override def hashCode =
      System.identityHashCode(value)
  }

  private def wrap[A](key: A) =
    new Wrapper(key)
}


Answer 2:

处理这将改变什么平等意味着为类,如一种方式

scala> case class Example() {
  override def equals( that:Any ) = that match {
    case that:AnyRef => this eq that
    case _ => false
  }
}
defined class Example

scala> val m = new java.util.IdentityHashMap[Example, String]()
m: java.util.IdentityHashMap[Example,String] = {}

scala> m.put(Example(), "first!")
res1: String = null

scala> m.put(Example(), "second!")
res2: String = null

scala> import scala.collection.JavaConverters._
import scala.collection.JavaConverters._

scala> m.asScala
res3: scala.collection.mutable.Map[Example,String] = Map(Example() -> second!, Example() -> first!)

scala> m.asScala.toMap
res4: scala.collection.immutable.Map[Example,String] = Map(Example() -> second!, Example() -> first!)

或者,如果你不想改变平等的类,你可以做一个包装。

当然,这不会执行,以及一个使用地图eq ,而不是== ; 它可能是值得一问一....



文章来源: Convert java.util.IdentityHashMap to scala.immutable.Map