【问题标题】:Implement TreeMap: why can't I print my own defined case class?实现 TreeMap:为什么我不能打印自己定义的案例类?
【发布时间】:2018-03-09 00:37:37
【问题描述】:

我是 Scala 新手。

我正在尝试使用二叉搜索树来实现TreeMap

我发现我可以打印一个非空的TreeMap,但如果出现以下情况,代码将无法编译 我尝试打印Empty()(这是我定义的案例类)

错误信息是:

[error] test.scala:33:16: 类型不匹配;

[error] found : Nothing <:>

[错误] 必需:K => 有序[K]

[错误] println(Empty())

[错误] ^

[error] 发现一个错误

[error] (test:compileIncremental) 编译失败

我的源代码:

val tm:TreeMap[Int, String] = Node(Empty(), Empty(), 4, "ddd")
println(tm) // prints "4->ddd"
//println(Empty()) //This won't compile


abstract class TreeMap[K <% Ordered[K], +V] extends AbstractMap[K, V] {

//Implementation omitted.
    override def +[V1 >: V](key: (K, V1)): TreeMap[K, V1] = ......

    override def -(key: K): TreeMap[K, V] = ......

    override def get(key: K): Option[V] = ......

    override def iterator: Iterator[(K, V)] = ......
}

case class Empty[K <% Ordered[K]]() extends TreeMap[K, Nothing]
case class Node[K <% Ordered[K], +V](left: TreeMap[K, V], 
     right: TreeMap[K, V], key: K, value: V) extends TreeMap[K, V]

【问题讨论】:

    标签: scala treemap case-class


    【解决方案1】:

    有趣。

    很明显,Empty() 调用的类型解析存在问题。您可能知道,[A &lt;% Ordered[A]] 等价于[A](implicit ev: A =&gt; Ordered[A])(顺便说一下,不推荐使用视图绑定)。所以我重写了你的方法有点不同(部分实现了缺失的方法):

    import scala.collection.AbstractMap
    
    abstract class TreeMap[K, +V](implicit ev: K => Ordered[K])
      extends AbstractMap[K, V] {
      //Implementation omitted.
      override def +[V1 >: V](key: (K, V1)): TreeMap[K, V1] = this
      override def -(key: K): TreeMap[K, V] = this
      override def get(key: K): Option[V]
      override def iterator: Iterator[(K, V)]
    }
    
    
    case class Node[K, +V](left: TreeMap[K, V],
                           right: TreeMap[K, V],
                           key: K,
                           value: V)(implicit ev: K => Ordered[K]) 
      extends TreeMap[K, V] {
      override def get(key: K): Option[V] =
        if (key == this.key) Some(value)
        else None
    
      override def iterator: Iterator[(K, V)] =
        Iterator((key, value))
    }
    
    case class Empty[K](implicit ev: K => Ordered[K])
      extends TreeMap[K, Nothing] {
      override def get(key: K): Option[Nothing] = None
      override def iterator: Iterator[(K, Nothing)] = Iterator.empty
    }
    
    val tm: TreeMap[Int, String] =
      Node(Empty(), Empty(), 4, "ddd")
    val tm2: TreeMap[Int, String] = Empty()
    
    println(tm) // prints Map("4->ddd")
    println(tm2) // prints Map()
    println(Empty[Nothing]()) //prints Map()
    //println(Empty()) //This won't compile
    

    如您所见,即使调用Empty[Nothing]() 也有效。我希望Empty() 应该以类似的方式工作,但不是。为了理解原因,我使用了scalac options -Xprint:typer -Ydebug -Xprint-types -Ytyper-debug 来查看代码的差异:

    object SomeClass extends App {
      case class Something3[T](implicit ev: T => Ordered[T])
    
      Something3()
    }
    

    object SomeClass extends App {
      case class Something3[T](implicit ev: T => Ordered[T])
    
      Something3[Nothing]()
    }
    

    解析类型时看起来像编译器首先尝试解析隐式参数(这是T =&gt; Ordered[T]而不是Nothing =&gt; Ordered[Nothing]并得到Nothing =&gt; Nothing),然后输入T,然后你会看到错误(这是我的了解我所看到的比较输出,而无需深入了解编译器术语)。

    我检查了scala.collections.immutable.TreeMap 的实现,他们在后台使用委托实现了它。

    正如我所见,如果您想将AbstractMap 用作父级,则无法避免将Key 类型用于Empty。并且更改 K 的差异也是不可能的。我想一旦它是编译时错误,你可以保持原样(如果它是你的实现中唯一的问题),并在评论中注明独立的Empty 应该为Key 显式输入类(有意义的类或Nothing)。

    【讨论】:

      【解决方案2】:

      问题是你添加了一个类型参数和一个绑定到Empty的视图,但是你没有在该行提供兼容的类型(也无法推断)

      println(Empty())
      

      可以在上一行推断出兼容的类型:

       Node(Empty(), Empty(), 4, "ddd")
      

      我认为正确的解决方法是将Empty() 的密钥类型固定为Nothing,并使TreeMap 在密钥类型中协变,即

      abstract class TreeMap[+K <% Ordered[K], +V] ...
      
      case class Empty() extends TreeMap[Nothing, Nothing]
      

      您也可以将 Empty 设为 case 对象,而不是类,因为它是常量:

      case object Empty extends TreeMap[Nothing, Nothing]
      

      【讨论】:

      • 无法将Empty 转换为对象。因为K 在 AbstractMap 父级中是不变的
      猜你喜欢
      • 2019-09-07
      • 2010-11-05
      • 2013-11-02
      • 2018-02-05
      • 2015-11-16
      • 2016-03-03
      • 1970-01-01
      • 2014-07-06
      • 1970-01-01
      相关资源
      最近更新 更多