所以我进入Scala并且我有一个问题,如果我想做什么是可能的,或者是否有更好的方法。
我希望能够将一个Map作为参数,其键是字符串,或者0-args函数返回一个字符串。例如,
def main(args: List[String]){
f = F(
Map(
"key" -> "value",
"key2" ->(()=> {"valule2"})
)
)
println(f("key"))
}
case class F(arg: Map[String, ???]){
def apply(s: String): String = {arg(s)}
}
这显然无法编译。有没有办法做到这一点?
答案 0 :(得分:8)
在这种情况下,您可以使用scala.Either
scala> val map: Map[String, Either[String, () => String]] = Map.empty
map: Map[String,Either[String,() => String]] = Map()
scala> map + ("key" -> Left("value"))
res0: scala.collection.immutable.Map[String,Either[String,() => String]] = Map(key -> Left(value))
scala> res0("key")
res1: Either[String,() => String] = Left(value)
scala> map + ("key2" -> Right(() => "value2"))
res2: scala.collection.immutable.Map[String,Either[String,() => String]] = Map(key2 -> Right(<function0>))
scala> res2("key2")
res3: Either[String,() => String] = Right(<function0>)
您可以使用类似的东西隐藏调用者的实现。
def toEither[T <: Any : Manifest](x: T): Either[String, () => String] =
x match {
case x: String => Left(x)
case x: Function0[String] if manifest[T] <:< manifest[() => String] => Right(x)
case _ => throw new IllegalArgumentException
}
Function0
的实际类型因类型删除而被删除,但可以使用Manifest
scala> map + ("key" -> toEither("value"))
res1: scala.collection.immutable.Map[String,Either[String,() => String]] = Map(key -> Left(value))
scala> map + ("key2" -> toEither(() => "value2"))
res2: scala.collection.immutable.Map[String,Either[String,() => String]] = Map(key2 -> Right(<function0>))
scala> res2("key2").right.get()
res3: String = value2
scala> map + ("key2" -> toEither(() => 5))
java.lang.IllegalArgumentException
scala> map + ("key2" -> toEither(false))
java.lang.IllegalArgumentException
由于@Submonoid在下面的评论中正确地纠正了我,因此有更简单的方法来处理Either
。
type StringOrFun = Either[String, () => String]
implicit def either(x: String): StringOrFun = Left(x)
implicit def either(x: () => String): StringOrFun = Right(x)
val m: Map[String, StringOrFun] = Map("key" -> "value", "key2" -> (() => "value2"))
答案 1 :(得分:3)
或者,您可以将任何字符串包装在一个计算结果为该字符串的函数中:
implicit def delayed[A](a : A) = () => a
val m = Map[String, () => String]("a" -> "b", "c" -> (() => "d"))