当我使用布尔值和字符串创建混合Map时:
scala> val map = Map('boolean -> true, 'string -> "string")
map: scala.collection.immutable.Map[Symbol,Any] = Map('boolean -> true, 'string -> string)
我尝试直接访问布尔部分,我得到:
scala> if (map('boolean)) true else false
<console>:9: error: type mismatch;
found : Any
required: Boolean
if (map('boolean)) true else false
^
所以我必须定义一个隐含的来使它工作:
scala> implicit def anyAsBoolean(x: Any) = x.asInstanceOf[Boolean]
warning: there were 1 feature warning(s); re-run with -feature for details
anyAsBoolean: (x: Any)Boolean
scala> if (map('boolean)) true else false
res3: Boolean = true
有没有办法让这个Map做隐式转换而不必在客户端代码中添加隐式部分?
答案 0 :(得分:4)
您可以尝试Shapeless HMap
:
class BiMapIS[K, V]
implicit val intToString = new BiMapIS[Int, String]
implicit val stringToInt = new BiMapIS[String, Int]
val hm = HMap[BiMapIS](23 -> "foo", "bar" -> 13)
//val hm2 = HMap[BiMapIS](23 -> "foo", 23 -> 13) // Does not compile - strong type
scala> hm.get(23)
res0: Option[String] = Some(foo)
scala> hm.get("bar")
res1: Option[Int] = Some(13)
因此,客户端不需要显式地转换Map或编写任何隐式转换(intToString,stringToInt仅用于映射定义)。请注意,HMap的类型将与{Int -> String, String -> Int}
绑定,您也无法执行{String -> A; String -> B}
,因此如果可能,应将字符串替换为某些案例对象。
答案 1 :(得分:3)
为什么不把它直接放在那里:
map('boolean).asInstanceOf[Boolean]
或者您可以使用Either
来保留类型信息:
val map: Map[Symbol, Either[Any, Boolean]] = Map(
'boolean -> Right(true),
'string -> Left("string"))
map('boolean).fold(throw new IllegalStateException(_), b => b)
使用Scalaz:
val map: Map[Symbol, Either[Any, Boolean]] = Map(
'boolean -> true.right[Any],
'string -> "string".left[Boolean])
map 'boolean | throw new IllegalStateException
答案 2 :(得分:0)
所以我最终从Map[Symbol, Any]
继承并以这种方式进行提取:
scala> :paste
// Entering paste mode (ctrl-D to finish)
object OptionMap {
def apply(options_map: Map[Symbol, Any]) = new OptionMap(options_map)
def apply(kv: (Symbol, Any)*) = new OptionMap(kv.toMap)
}
class OptionMap(options_map: Map[Symbol, Any]) extends Map[Symbol, Any] {
def apply[T](name: Symbol) : T = options_map(name).asInstanceOf[T]
def get[T](name: Symbol) : T = options_map(name).asInstanceOf[T]
def get(name: Symbol) : Option[Any] = options_map.get(name)
override def contains(name: Symbol): Boolean = options_map.contains(name)
def +[B1 >: Any](kv: (Symbol, B1)): OptionMap = OptionMap(options_map + kv)
def -(key: Symbol): OptionMap = OptionMap(options_map - key)
def iterator = options_map.iterator
}
// Exiting paste mode, now interpreting.
defined module OptionMap
defined class OptionMap
scala> val omap = OptionMap('boolean -> true, 'string -> "string", 'int -> 5, 'double -> 3.14)
omap: OptionMap = Map('boolean -> true, 'string -> string, 'int -> 5, 'double -> 3.14)
scala> if(omap.contains('boolean) && omap('boolean)) true else false
res0: Boolean = true
scala> omap[String]('string) + " world!"
res1: String = string world!
scala> omap[Int]('int) + 3
res2: Int = 8
scala> omap[Double]('double) + 3
res3: Double = 6.140000000000001
scala> omap + ('extra -> true)
res4: OptionMap = Map('string -> string, 'double -> 3.14, 'boolean -> true, 'int -> 5, 'extra -> true)
scala> omap - 'extra
res5: OptionMap = Map('boolean -> true, 'string -> string, 'int -> 5, 'double -> 3.14)
所以它现在做我想要的,客户端代码不需要有任何暗示。当然,客户端需要知道每个key -> value
对中存储的类型,但这应该是。