将Ordering扩展为容纳类对象时,PriorityQueue varargs错误

时间:2018-12-31 16:55:54

标签: scala variadic-functions priority-queue

我的目标是创建一个在初始化包含上述对象的PriorityQueue时使用2个或更多对象的可变参数的函数。

相关代码为:

case class Topic(topic: String, usageFrequency: Long = 1)  

object FreqOrdering extends Ordering[Topic] {
  def compare(a: Topic, b:Topic) = -(a.usageFrequency compare b.usageFrequency)}  

def initPriQu(a : Topic, b: Topic, c: Topic*): PriorityQueue[Topic] = {
return PriorityQueue(a,b,c)(FreqOrdering)}

sbt错误(Scala 2):

  

[错误]发现:TopicTrenderInit.FreqOrdering.type
  [错误]必需:scala.math.Ordering [等于]
  [错误]注意:TopicTrenderInit.Topic <:等于(和TopicTrenderInit.FreqOrdering.type <:scala.math.Ordering [TopicTrenderInit.Topic]),但特征排序在T类型中不变。
  [错误]您可能希望调查诸如_ <: Equals之类的通配符类型。 (SLS 3.2.10)
  [错误]返回PriorityQueue(a,b,c)(FreqOrdering)
  [错误] ^
  [错误] /home/aaron-laptop/Documents/Scala/topic_trender100/src/main/scala/main.scala:48:25:类型不匹配;
  发现[错误]:scala.collection.mutable.PriorityQueue [Equals]
  [错误]必需:scala.collection.mutable.PriorityQueue [TopicTrenderInit.Topic]
  [错误]注意:等于>:TopicTrenderInit.Topic,但是类PriorityQueue在类型A中是不变的。
  [错误]您可能希望调查诸如_ >: TopicTrenderInit.Topic之类的通配符类型。 (SLS 3.2.10)
  [错误]返回PriorityQueue(a,b,c)(FreqOrdering)

当没有'*'表示可变参数时,一切正常,没有错误。我认为最令我感到困惑的是:我看到的scala.math.Ordering [Equals]错误。我还阅读了一篇有关模式匹配的文章,但是我觉得我必须阅读更多有关它的内容才能理解实现。这是怎么回事?
谢谢。

2 个答案:

答案 0 :(得分:5)

问题在于您构建PriorityQueue的方式。您要向其传递两个Topic类型的值和一个Seq[Topic]类型的值,因此结果为PriorityQueue[Any]

这应该有效:

def initPriQu(a : Topic, b: Topic, c: Topic*): mutable.PriorityQueue[Topic] =
  mutable.PriorityQueue(Seq(a, b) ++ c:_*)(FreqOrdering)

此外,请勿使用return

答案 1 :(得分:1)

问题在于,当您将a, b, c传递到PriorityQueue Factory 时。编译器看到的是,您传递了三个A类型的参数,而这些树之间唯一的超级类型是Equals
这是因为abTopics,作为案例类扩展了Equals,而c的类型是Seq[Topic] (varargs参数作为Seq传递),它也扩展了Equals
这就是为什么它要求Ordering[Equals]

您可以按以下步骤进行修复。
(请注意,这很丑陋,可能很简单,您可以考虑只接收一个vararg,而不是ab然后再c

// It will be good to have this as an implicit so you don't have to pass it explicitly
// every time you need to.
// And it is always preferable to have an implicit val with an explicit type signature
// than an implicit object.
implicit val TopicOrdering: Ordering[Topic] = new math.Ordering[Topic] {
  override def compare(a: Topic, b:Topic): Int =
    -(a.usageFrequency compare b.usageFrequency)
}

import scala.collection.mutable.PriorityQueue
def initPriQu(a: Topic, b: Topic, others: Topic*): PriorityQueue[Topic] =
  // 1. Don't use return in scala.
  // 2. Here I made a Seq of Seqs of Topic - Seq[Seq[Topic]]
  //    then I flatten it to have a Seq of Topic - Seq[Topic]
  //    and finally used the ':_*' operator to turn a Seq into a varargs.
  PriorityQueue((Seq(a, b) ++ others): _*)