我为了不耐烦的人而从斯卡拉那里做了一些练习'预订并偶然发现了这个魔法。我有一个简单的scala对象来执行代码:
object Main {
def main(args: Array[String]): Unit = {
println(charIndex("Missisipi"))
//var s = scala.collection.immutable.SortedSet[Int]()
}
def charIndex(s: String) : scala.collection.mutable.Map[Char, scala.collection.mutable.TreeSet[Int]] = {
val m = scala.collection.mutable.Map[Char, scala.collection.mutable.TreeSet[Int]]()
s.zipWithIndex.foreach{
case (c, i) => m += c -> (m.getOrElse(c, scala.collection.mutable.TreeSet()) += i)
}
m
}
}
无论它看起来如何(我以最丑陋的方式做到了),但在这种情况下它不会编译错误:
错误:(14,80)分散了类型的隐式扩展 scala.math.Ordering [T1]从对象Ordering中的方法Tuple9开始 case(c,i)=> m + = c - > (m.getOrElse(c,scala.collection.mutable.TreeSet())+ = i)错误:(14,80)不够 方法的参数适用:(隐式ord: scala.math.Ordering [A])类中的scala.collection.mutable.TreeSet [A] SortedSetFactory。未指定的值参数ord。 case(c,i)=> m + = c - > (m.getOrElse(c,scala.collection.mutable.TreeSet())+ = i)
但是如果你在main方法中取消注释,它将被成功编译。为什么会这样?
答案 0 :(得分:3)
如果您使用-Xlog-implicits
运行此示例(对于sbt scalacOptions := Seq( "-Xlog-implicits" )
),您会看到很多[info]
这样的消息
math.this.Ordering.Tuple6不是scala.math.Ordering [A]的有效隐含值,因为: [info]对scala.math.Ordering [T1]
类型的隐式扩展进行分歧
这基本上适用于math.this.Ordering
中的所有类型,例如Boolean
到Iterables
和Options
。
它告诉我们编译器在TreeSet
失败时疯狂地试图猜测你试图构造的getOrElse
类型。在您的示例中,它只是TreeSet
没有任何[explicit]
类型,因此编译器必须找到一个隐式类型来绑定新的TreeSet
。通过在Int
构造函数中指定TreeSet
,您将消除对implicits的搜索,代码将无任何魔法。
case ( c, i ) => m += c -> ( m.getOrElse( c, scala.collection.mutable.TreeSet[Int]() ) += i)
现在,重点是。
您指定m
是Map
到TreeSet[Int]
,这很好,但.getOrElse
会在m
无效时返回scala.collection.mutable.TreeSet()
的默认值第一个角色。要构造该默认值,它将使用您提供的定义
.getOrElse
在TreeSet
的文档中,我们可以see对于默认值编译器将使用从第二个参数计算得到的结果。 new TreeSet()(implicit ord: Ordering[A])
need的构造函数,要知道要在该集合中保留哪种类型的值,如果未能看到明确的定义,它将查找含义。
Ordering
正如我在开头提到的那样,它会强制执行TreeSet
中所有可能的类型,因为,你知道,它必须是面向订单的类型,但棘手的部分是它不知道它实际需要什么类型。编译器必须先构建一个新的+= i
才能i
。它不能只是期待,看到Int
是TreeSet[Int]
,构建i
并返回添加SortedSet
。这将是一个真正的魔术。
关于scala如何确定隐式参数的类型,有一个很棒的post。请注意,TreeSet
已通过traits连接到SortedTree[Int]
,因此无法进入类别“T的某些部分”。在这种特殊情况下,编译器将看到明确定义的Int
,因为没有其他选项将使用TreeSet
作为console.log(width4[0].clientWidth);
的隐式类型。