Scala:创建通用集合的问题

Posted

技术标签:

【中文标题】Scala:创建通用集合的问题【英文标题】:Scala: Problems creating generic collection 【发布时间】:2021-04-27 06:25:42 【问题描述】:

我有两个排序列表,并且想要创建一个迭代器,它将两个列表合并为排序后的顺序。我是 Scala 的新手,尤其是编写泛型类的新手。我收到一个我无法弄清楚的编译错误。

这是 MergingIterator 的代码

class MergingIterator[ElementType <: Ordered[ElementType]] (iterator1: BufferedIterator[ElementType], iterator2: BufferedIterator[ElementType]) extends Iterator[ElementType]


 override def hasNext: Boolean = 
   iterator1.hasNext || iterator2.hasNext
 

 override def next(): ElementType = 
   if(!iterator1.hasNext && !iterator2.hasNext)
    throw new IllegalStateException("All iterators empty.  No next element")
   
   val e1 : Option[ElementType] = if(iterator1.hasNext) Some(iterator1.head) else None
   val e2 : Option[ElementType] = if(iterator2.hasNext) Some(iterator2.head) else None
   if(e1.isDefined && e2.isDefined)
     val e1a = e1.get
     val e2a = e2.get
     if(e1a.equals(e2a) || e1a < e2a)
       iterator1.next()
     
     else 
       iterator2.next()
     
   
   else if (e1.isDefined)
     iterator1.next
   
   else if (e2.isDefined)
     iterator2.next()
   
   else
     throw new Exception("InvalidState.  No elements present")
   
 

这里是单元测试,它不能编译:

class MergingIteratorTest extends AnyFunSuite 

  test("Both Iterators Empty")
    runTest(List(), List(), List())
  

  private def runTest(vals1 : List[ComparableInt], vals2: List[ComparableInt], expected: List[ComparableInt]): Unit =
    val it1 = vals1.iterator.buffered
    val it2 = vals2.iterator.buffered
    val merging = new MergingIterator[ComparableInt](it1, it2)
    val merged = merging.toList
    assert(expected.equals(merged))
  

  case class ComparableInt(value: Int) extends Ordered[Int] 
    override def compare(that: Int): Int = value - that
  


但是,当我尝试编译时,出现以下错误。

Error:(14, 9) type arguments [MergingIteratorTest.this.ComparableInt] do not conform to class MergingIterator's type parameter bounds [ElementType <: Ordered[ElementType]]
    val merging = new MergingIterator[ComparableInt](it1, it2)
Error:(14, 23) type arguments [MergingIteratorTest.this.ComparableInt] do not conform to class MergingIterator's type parameter bounds [ElementType <: Ordered[ElementType]]
    val merging = new MergingIterator[ComparableInt](it1, it2)

我确定我做错了一些愚蠢的事情,但由于我缺乏使用 scala 的经验,我已经能够找出问题所在。如有任何帮助,我们将不胜感激。

【问题讨论】:

最好使用Ordering,它是typeclass,而不是Ordered 【参考方案1】:

你需要做

case class ComparableInt(value: Int) extends Ordered[ComparableInt] 
    override def compare(that: ComparableInt): Int = value.value - value.value

问题出在 [ElementType &lt;: Ordered[ElementType]] 类型边界中 - 你看到 ElementType 应该对自己排序,而你的情况 ComparableInt 实现 Ordered[Int] 并且意思 ComparableInt 不是 Ordered 对自己作为 MergingIterator 签名预计。

【讨论】:

【参考方案2】:

Ordering 类型类相同。

class MergedIterator[ElmTyp:Ordering](itrA: Iterator[ElmTyp]
                                     ,itrB: Iterator[ElmTyp]
                                     ) extends Iterator[ElmTyp] 
  import Ordering.Implicits._
  private val itr1 = itrA.buffered
  private val itr2 = itrB.buffered

  override def hasNext: Boolean = itr1.hasNext || itr2.hasNext
  override def next(): ElmTyp =
    if      (!itr1.hasNext)         itr2.next()
    else if (!itr2.hasNext)         itr1.next()
    else if (itr1.head > itr2.head) itr2.next()
    else                            itr1.next()

【讨论】:

以上是关于Scala:创建通用集合的问题的主要内容,如果未能解决你的问题,请参考以下文章

Scala集合

Scala:如何从某个集合创建 XML 节点

了解Scala集合概念,掌握Traversable的用法

Scala学习 —— 元组&映射

Scala 自定义集合返回 null 列表作为默认值

scala:集合常用函数