用于类型安全,基于类型类的Scala映射的Java API?

时间:2016-05-01 11:55:31

标签: java scala dictionary type-safety

我们使用类似下面的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不匹配。

任何建议都将不胜感激。

0 个答案:

没有答案