字典我的意思是从名称到值的轻量级映射,可以用作方法的返回值。
我所知道的选项包括制作案例类,创建anon对象以及从字符串制作地图 - >任何。
有什么更好的吗?
理想情况下,这些可以从json构建,并在适当时转换回它。
我不需要静态输入(虽然它会很好,我可以看到它是不可能的) - 但我确实想避免显式转换。
答案 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]]]
,但这种语法显然无法很好地扩展。如果你有更多类型,你可以使用像...这样的东西。