我们使用类似下面的Scala代码来实现键和值的类型安全映射。此映射的实例作为actor消息发送并存储在Redis和HornetQ等中。现在我们需要提供Java(8)API的新要求。这是相当棘手的,因为Java和Scala类型之间存在差异,而且当从Java调用Scala时,您无法从Scala编译器获得帮助。以下是Scala中基本的类型安全密钥和映射定义:
abstract case class Key(name: String) extends Serializable {
type Value
}
object Key {
type Aux[A] = Key { type Value = A }
def create[A](name: String): Key.Aux[A] = new Key(name) {
type Value = A
}
}
case class TypeSafeMap(data: Map[Key, Any] = Map.empty) extends Serializable {
def get[A](key: Key): Option[key.Value] =
data.get(key).asInstanceOf[Option[key.Value]]
def set[A](key: Key.Aux[A], value: A): TypeSafeMap =
TypeSafeMap(data + (key → value))
}
用法:
val myKey1 = Key.create[Double]("myKey1")
val myKey2 = Key.create[Int]("myKey2")
val myKey3 = Key.create[String]("myKey3")
val myMap = TypeSafeMap()
.set(myKey1, 12.3)
.set(myKey2, 42)
.set(myKey3, "hello")
上述代码与Java不兼容。我们可以添加一个方法 像这样用于Java,但它会丢掉所有类型安全:
final def jset(key: Key, value: Any): TypeSafeMap = {
TypeSafeMap(data + (key → value))
}
另一种选择是使用与Java更兼容的泛型类型:
case class Key[A](name: String, typ: Class[A]) extends Serializable {
override def toString = name
}
object Key {
def create[A](name: String, typ: Class[A]): Key[A] =
new Key[A](name, typ)
}
case class TypeSafeMap(data: Map[Key[_], Any] = Map.empty) extends Serializable {
def get[A](key: Key[A]): Option[A] =
data.get(key).asInstanceOf[Option[A]]
def set[A](key: Key[A], value: A): TypeSafeMap =
TypeSafeMap(data + (key → value))
}
这种类型适用于Scala和Java,但是限制您使用具有Class对象的类型,我认为它将数组和集合排除为值类型。 我想解决方法是在这些情况下需要包装类。
另一个问题是原始类型:例如,如果将Key的值类型定义为Scala Int,则它将与java.lang.Integer不匹配。
任何建议都将不胜感激。