Martin Odersky的ScalaDay 2011的例子:获得地图?
我正在通过
Odersky’s ScalaDays 2011 keynote talk工作,当我到达这条特定的行(分配charCode)时,他构建了一个非常少的代码行的电话号码同义词生成器:
val mnem: Map[Char,String] = // phone digits to mnemonic chars (e.g. '2' -> "ABC") val charCode: Map[Char,Char] = for ((digit,str) <- mnem; letter <- str) yield (letter -> digit) // gives ('A','2'),('B','2') etc 为什么类型为Map的charCode? 当我在其他例子中产生元组时,我只是获得一系列元组,而不是地图。例如: scala> for (i <- 1 to 3) yield (i -> (i+1)) res16: scala.collection.immutable.IndexedSeq[(Int,Int)] = Vector((1,2),(2,3),(3,4)) 人们可以很容易地将它转换成具有toMap()的地图,就像… scala> (for (i <- 1 to 3) yield (i -> (i+1))).toMap res17: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2,2 -> 3,3 -> 4) …但不知何故,Odersky的例子避免了这一点。 什么Scala魔法,如果有的话,我俯瞰这里? 附录1:隐式转换?我想添加一些关于Oxbow Lake的评论的细节(注意:我的评论可能会部分错误,略有误解,也许是他所得到的)。 我怀疑由于需要地图而发生某种隐式转换。所以我在翻译中尝试过Odersky的迭代器,没有提示它应该产生什么: scala> val mnem = Map('2' -> "ABC",'3' -> "DEF",'4' -> "GHI") // leaving as a map,still scala> for ((digit,str) <- mnem; letter <- str) yield (letter,digit) res18: scala.collection.immutable.Map[Char,Char] = Map(E -> 3,F -> 3,A -> 2,I -> 4,G -> 4,B -> 2,C -> 2,H -> 4,D -> 3) (请注意,我在这里离开mnem作为地图。) 同样,告诉编译器我想要一个地图没有改变我自己的结果: scala> val x: Map[Int,Int] = for (i <- 1 to 3) yield (i -> (i+1)) <console>:7: error: type mismatch; found : scala.collection.immutable.IndexedSeq[(Int,Int)] required: Map[Int,Int] val x: Map[Int,Int] = for (i <- 1 to 3) yield (i -> (i+1)) 另一方面,遵循东方的提示(这似乎也是OL所说的),以下(dorky)修改确实产生了一个地图: scala> for ((i,j) <- Map(1 -> 2,2 -> 2)) yield (i -> (i+1)) res20: scala.collection.immutable.Map[Int,2 -> 3) 所以如果迭代的值来自地图,那么地图是不是会产生的? 我希望通过以下方式来理解答案:(a)将“for”循环转换为其长时间的等价物(一个调用/调用映射)和(b)了解什么意义被神奇地引用。 附录2:统一返回类型:(huynhjl :)那似乎是这样。我的第一个例子转换为 (1 to 3).map(i => (i,i+1)) // IndexedSeq[(Int,Int)] 而第二个变成类似于这样的东西: Map(1 -> 2,2 -> 2).map(i => (i._1,i._1+1)) // Map[Int,Int] 那么“Map.map”的类型就是 def map [B,That] (f: ((A,B)) ? B)(implicit bf: CanBuildFrom[Map[A,B],B,That]): That 啊,琐事;-) 附录3:好的,那太简单了吧。 Miles Sabin提供了一个更正确的desugaring,在下面。更微不足道;-) 解决方法
了解你为什么得到一个地图回来比较容易理解,
val charCode: Map[Char,str) <- mnem; letter <- str) yield (letter -> digit) 相当于, val charCode = mnem.flatMap { case (digit,str) => str.map { letter => (letter -> digit) } } 因此,这里为charCode推断的类型将是应用于Map的flatMap的结果类型。 flatMap的签名相当复杂, def flatMap [B,That] (f: ((A,B)) => GenTraversableOnce[B]) (implicit bf: CanBuildFrom[Map[A,That]): That 因为它提供了Scala编译器需要计算适当结果类型的基础架构,因为Map的类型和函数的类型(Flat)Map’跨越它。 如其他地方所述,集合框架的设计方式使得集装箱将(平面)映射到尽可能相同形状的容器。在这种情况下,我们映射Map [Char,String],因此它的元素相当于对(Char,String)。我们映射的函数是生成对(Char,Char),它们连接可以给我们一个Map [Char,Char]。 我们可以通过查找相应的CanBuildFrom实例来验证编译器是否也相信这一点, scala> import scala.collection.generic.CanBuildFrom import scala.collection.generic.CanBuildFrom scala> implicitly[CanBuildFrom[Map[Char,String],(Char,Char),Map[Char,Char]]] res0: scala.collection.generic.CanBuildFrom[Map[Char,Char]] = scala.collection.generic.GenMapFactory$MapCanBuildFrom@1d7bd99 请注意,CanBuildFrom的最后一个参数是Map [Char,Char]。这将在flatMap的签名中修复“That”类型的参数,这给了我们这个flatMap的结果类型,因此推断出charCode的类型。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |