在scala中创建和传递包含多个类型的字典的最佳方法是什么?

时间:2011-08-02 20:47:29

标签: scala

字典我的意思是从名称到值的轻量级映射,可以用作方法的返回值。

我所知道的选项包括制作案例类,创建anon对象以及从字符串制作地图 - >任何。

  • 案例类需要精神开销才能创建(名称),但需要强类型。
  • Anon对象似乎没有很好的文档,我不清楚如何将它们用作参数,因为没有命名类型。
  • 字符串中的地图 - >任何需要铸造以便检索。

有什么更好的吗?

理想情况下,这些可以从json构建,并在适当时转换回它。

我不需要静态输入(虽然它会很好,我可以看到它是不可能的) - 但我确实想避免显式转换。

4 个答案:

答案 0 :(得分:3)

以下是您想要的基本问题:

def get(key: String): Option[T] = ...

val r = map.get("key")

r的类型将从get的返回类型定义 - 那么,该类型应该是什么?从哪里可以定义?如果你把它作为一个类型参数,那么它相对容易:

import scala.collection.mutable.{Map => MMap}
val map: MMap[String, (Manifest[_], Any) = MMap.empty
def get[T : Manifest](key: String): Option[T] = map.get(key).filter(_._1 <:< manifest[T]).map(_._2.asInstanceOf[T])
def put[T : Manifest](key: String, obj: T) = map(key) = manifest[T] -> obj

示例:

scala> put("abc", 2)

scala> put("def", true)

scala> get[Boolean]("abc")
res2: Option[Boolean] = None

scala> get[Int]("abc")
res3: Option[Int] = Some(2)

问题当然是,您必须告诉编译器您希望在该键下的地图上存储哪种类型。不幸的是,没有办法解决这个问题:编译器无法知道在编译时该键下将存储的类型。

你采取的任何解决方案都会遇到同样的问题:不知何故,你必须告诉编译器应该返回什么类型。

现在,这不应该成为Scala计划的负担。取上面的r ...然后你会用r来做某事,对吧?您正在使用它的方法将具有适合某种类型的方法,并且由于您知道方法是什么,因此您还必须知道r的类型必须是什么。

如果不是这种情况,那么代码就会出现根本性的错误 - 或许,您可能没有希望地图知道您将如何处理它。

答案 1 :(得分:2)

所以你想解析json并把它变成类似于json输入中描述的javascript objets的对象?如果你想要静态类型,case类几乎是你唯一的选择,并且已经有了库处理它,例如lift-json。

另一种选择是使用Scala 2.9的动态类型实验支持。这将以牺牲类型安全为代价为您提供优雅的语法。

答案 2 :(得分:2)

当您将类型参数显式传递给get方法并将实际值转换为get方法时,您可以使用我在the casbah library中看到的方法。这是一个简单的例子:

case class MultiTypeDictionary(m: Map[String, Any]) {
  def getAs[T <: Any](k: String)(implicit mf: Manifest[T]): T =
    cast(m.get(k).getOrElse {throw new IllegalArgumentException})(mf)
private def cast[T <: Any : Manifest](a: Any): T = a.asInstanceOf[T] }
implicit def map2multiTypeDictionary(m: Map[String, Any]) = MultiTypeDictionary(m)
val dict: MultiTypeDictionary = Map("1" -> 1, "2" -> 2.0, "3" -> "3")
val a: Int = dict.getAs("1") val b: Int = dict.getAs("2") //ClassCastException val b: Int = dict.getAs("4") //IllegalArgumetExcepton

您应该注意到没有真正的编译时检查,因此您必须处理所有异常缺陷。

UPD 使用MultiTypeDictionary类

答案 3 :(得分:1)

如果您只有有限数量的类型可以作为值出现,您可以使用某种类型的联合类型(a.k.a。不相交类型),例如一个Map[Foo, Bar | Baz | Buz | Blargh]。如果您只有两种可能性,则可以使用Either[A,B],为您提供Map[Foo, Either[Bar, Baz]]。对于三种类型,您可能会欺骗并使用Map[Foo, Either[Bar, Either[Baz,Buz]]],但这种语法显然无法很好地扩展。如果你有更多类型,你可以使用像...这样的东西。