Scala如何确定TreeSet构造函数的隐式类型参数

丹尼斯·洛什卡列夫(Denis Loshkarev)

我正在从《 Scala for the不耐烦》这本书中做练习,偶然发现了这种魔术。我有一个用于执行代码的简单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]的隐式扩展从对象中的方法Tuple9开始排序对象排序情况(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。情况(c,i)=> m + = c->(m.getOrElse(c,scala.collection.mutable.TreeSet())+ = i)

但是,如果您在主方法中取消注释行,它将成功编译。为什么会这样呢?

丹尼斯·蔡

问题的核心

如果使用-Xlog-implicits(for sbt scalacOptions := Seq( "-Xlog-implicits" )运行此示例,您将看到很多[info]类似这样消息

math.this.Ordering.Tuple6不是scala.math.Ordering [A]的有效隐式值,因为:[info]发散了scala.math.Ordering [T1]类型的隐式扩展

这基本上适用于math.this.Ordering从简单喜欢BooleanIterables和的每种类型Options

它告诉我们,编译器疯狂地尝试猜测失败TreeSet时尝试构造的类型getOrElse在您的示例中,它只是一个TreeSet没有任何[explicit]键入的内容,因此编译器必须找到一个隐式类型以将new绑定TreeSet该类型通过IntTreeSet构造函数中指定您将消除对隐式的搜索,并且代码将毫无魔法地工作

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

现在,到重点。

编译器如何搜索隐式,也就是为什么这种魔术有效

您指定的mMapto TreeSet[Int],这很好,但是在无法获取第一个字符时.getOrElse将返回默认值m要构造该默认值,它将使用您提供的定义

scala.collection.mutable.TreeSet()

在docs中,.getOrElse我们可以看到,对于默认值,编译器将使用第二个参数计算产生的结果。TreeSet 需要知道要在该集合中保留哪种类型的值的构造函数,如果它无法看到显式定义,它将寻找隐式值。

new TreeSet()(implicit ord: Ordering[A])

正如我在开始时提到的那样,它将暴力破解所有可能的类型,Ordering因为您必须知道它必须是面向订单的类型,但棘手的部分是它不知道实际需要哪种类型。编译器必须建立一个新的TreeSet,才能够+= i给它。它不能只是期待,看到iInt,构建TreeSet[Int]并取回添加i到它。那将是一个真正的魔术。

关于scala如何确定隐式参数的类型的文章很棒请注意,SortedSet通过特征连接TreeSet特征因此它无法归入“ T的某些部分”类别。在这种特殊情况下,编译器将看到一个显式定义,SortedTree[Int]并且由于没有其他选项将Int用作的隐式类型TreeSet

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章