将隐式转换应用于地图

时间:2016-11-11 14:21:15

标签: scala implicit-conversion implicit

我在以下示例中尝试了隐式转换:

val m: Map[Int, Int] = Map(10 -> "asd")  //fine
val mm: Map[Int, Int] = Map("asd" -> 20) //type mismatch; found: (String, Int) 
                                         //required: (Int, Int)

implicit def stringToInt(str: String): Int = 10

为什么我们无法将隐式转换应用于地图键?有办法解决这个问题吗?

3 个答案:

答案 0 :(得分:5)

它不起作用,因为您使用的是->(内联)运算符:

implicit final class ArrowAssoc[A](self : A) extends scala.AnyVal {
  @scala.inline
  def ->[B](y : B) : scala.Tuple2[A, B] = { /* compiled code */ }
  def →[B](y : B) : scala.Tuple2[A, B] = { /* compiled code */ }
}

您可以看到,在评估B时,A已经“固定”。我们只是说,在使用->运算符时,您只能(隐式)转换元组的右侧:

implicit def stringToInt(str: String): Int = 10  
implicit def intToStr(str: Int): String = "a"

val a: Map[Int, Int] = Map(10 -> "asd") //fine
val b: Map[Int, Int] = Map("asd" -> 20) // error! cant change left side

val c: Map[String, String] = Map("asd" -> 20) // fine 
val d: Map[String, String] = Map(10 -> "asd") // error! cant change left side

由于与使用运算符->相关的类似编译器怪癖,@ Jorg的解决方案在一个方向上工作,而在另一个方向上工作:

implicit def tupleIntifier(t: (String, Int)) = (10, 10)
implicit def tupleIntifier2(t: (Int, String)) = (10, 10)

val a: Map[Int, Int] = Map("asd" -> 20) // uses tupleIntifier
val b: Map[Int, Int] = Map(10 -> "asd") // fails!!

但是,如果您完全避免使用->运算符并只使用(key, value)语法,那么它将起作用:

val a: Map[Int, Int] = Map((10, "asd"))
val b: Map[Int, Int] = Map(("asd", 20))

implicit def stringToInt(str: String): Int = 15

println(a) // prints Map(10 -> 15)
println(b) // prints Map(15 -> 20)

答案 1 :(得分:2)

请查看您收到的错误消息:

error: type mismatch;
found   : (String, Int)
required: (Int, Int)
      val mm: Map[Int, Int] = Map("asd" -> 20)
                                        ^

错误消息关于String而非Int,大约是(String, Int)而不是(Int, Int)。所以,你只是转换错误的东西:

implicit def tupleIntifier[T](t: (String, T)) = (10, t._2)

val mm: Map[Int, Int] = Map("asd" -> 20)
//=> mm: Map[Int,Int] = Map(10 -> 20)

瞧!它有效。

答案 2 :(得分:1)

如果你要添加这样一般的隐式转换,你将失去Scala强制执行的类型安全性,因为任何String都可以在任何地方根据需要成为Int,而无需程序员的干预。 实际上,当您想要从其他数据创建该地图时,您可能已经知道该其他数据的数据类型。因此,如果已知键是整数,则将它们转换为Int并使用它们。否则,请使用字符串。 你的例子非常人为。你试图解决哪个具体问题?