scala如何确定TreeSet构造函数

时间:2017-10-23 17:34:50

标签: scala

我为了不耐烦的人而从斯卡拉那里做了一些练习'预订并偶然发现了这个魔法。我有一个简单的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方法中取消注释,它将被成功编译。为什么会这样?

1 个答案:

答案 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中的所有类型,例如BooleanIterablesOptions

它告诉我们编译器在TreeSet失败时疯狂地试图猜测你试图构造的getOrElse类型。在您的示例中,它只是TreeSet没有任何[explicit]类型,因此编译器必须找到一个隐式类型来绑定新的TreeSet。通过在Int构造函数中指定TreeSet,您将消除对implicits的搜索,代码将无任何魔法

case ( c, i ) =>  m += c -> ( m.getOrElse( c, scala.collection.mutable.TreeSet[Int]() ) += i)

现在,重点是。

编译器如何搜索implicits,这就是为什么这个魔法有效

您指定mMapTreeSet[Int],这很好,但.getOrElse会在m无效时返回scala.collection.mutable.TreeSet() 的默认值第一个角色。要构造该默认值,它将使用您提供的定义

.getOrElse

TreeSet的文档中,我们可以see对于默认值编译器将使用从第二个参数计算得到的结果。 new TreeSet()(implicit ord: Ordering[A]) need的构造函数,要知道要在该集合中保留哪种类型的值,如果未能看到明确的定义,它将查找含义。

Ordering

正如我在开头提到的那样,它会强制执行TreeSet中所有可能的类型,因为,你知道,它必须是面向订单的类型,但棘手的部分是它不知道它实际需要什么类型。编译器必须先构建一个新的+= i才能i。它不能只是期待,看到IntTreeSet[Int],构建i并返回添加SortedSet。这将是一个真正的魔术。

关于scala如何确定隐式参数的类型,有一个很棒的post。请注意,TreeSet已通过traits连接到SortedTree[Int],因此无法进入类别“T的某些部分”。在这种特殊情况下,编译器将看到明确定义的Int,因为没有其他选项将使用TreeSet作为console.log(width4[0].clientWidth); 的隐式类型。