Моя цель - создать функцию, которая принимает varargs из 2 или более объектов при инициализации PriorityQueue, содержащего указанные объекты.
Соответствующий код:
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):
[error] found : TopicTrenderInit.FreqOrdering.type
[error] required: scala.math.Ordering[Equals]
[error] Note: TopicTrenderInit.Topic <: Equals (and TopicTrenderInit.FreqOrdering.type <: scala.math.Ordering[TopicTrenderInit.Topic]), but trait Ordering is invariant in type T.
[error] You may wish to investigate a wildcard type such as_ <: Equals. (SLS 3.2.10)
[error] return PriorityQueue(a,b,c)(FreqOrdering)
[error] ^
[error] /home/aaron-laptop/Documents/Scala/topic_trender100/src/main/scala/main.scala:48:25: type mismatch;
[error] found : scala.collection.mutable.PriorityQueue[Equals]
[error] required: scala.collection.mutable.PriorityQueue[TopicTrenderInit.Topic]
[error] Note: Equals >: TopicTrenderInit.Topic, but class PriorityQueue is invariant in type A.
[error] You may wish to investigate a wildcard type such as_ >: TopicTrenderInit.Topic. (SLS 3.2.10)
[error] return PriorityQueue(a,b,c)(FreqOrdering)
Когда нет "*", указывающего на vararg, все работает, ошибок нет. Я думаю, что меня больше всего смущает то, что я вижу ошибку required: scala.math.Ordering [Equals]. Я также прочитал статью о сопоставлении с образцом, но мне кажется, что мне нужно будет прочитать об этом больше, чтобы понять реализацию. Что здесь происходит? Спасибо.





Проблема в том, что когда вы передаете a, b, c в ФабрикаPriorityQueue. Компиляторы видят, что вы передали три аргумента типа A, и единственный супертип между этими деревьями - Equals.
.
Это потому, что a и b - это Topics, который как класс случая расширяет Equals, а c относится к типу Seq[Topic](аргументы varargs передаются как Seq), который также расширяет Equals.
.
Вот почему он просит Ordering[Equals].
Вы можете исправить это следующим образом.
(Обратите внимание, это довольно уродливо и, возможно, неуместно, вы можете просто получить один varargs вместо a и b, а затем 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): _*)
Проблема в том, как вы собираете 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.
@ LuisMiguelMejíaSuárez, я думаю, что для List самой быстрой реализацией будет a +: b +: c:_*, потому что он будет использовать +: из List, который будет просто оболочкой для ::, то есть O(1). Однако для других базовых коллекций производительность может быть очень плохой, потому что может потребоваться 2 копии. Предлагаемый здесь ++ для List - это оболочка над :::, которая также будет неплохой без больших жертв для других возможных типов. AFAIK ваш flatten не переопределяется ни в одном классе, поэтому оптимизации нет вообще, и на самом деле сложнее добавить оптимизацию в flatten.
@SergGr после небольшого поиска я обнаружил, что varargs реализованы с использованием WrappedArray, а не List, поэтому да, решение Тима с использованием ++ будет лучшим. Я обновлю свой ответ, чтобы использовать его тоже.
спасибо, все эти комментарии поучительны. В чем причина не использовать ключевое слово return? Это для лучшей читаемости или по более функциональной причине?
@ A.Lopez Проблема с return заключается в том, что он не нужен в простых случаях и может иметь неожиданное поведение в сложных случаях. В простом случае вы можете просто использовать выражение в качестве возвращаемого значения. В сложных случаях он может выпрыгивать из нескольких вложенных блоков, и не всегда понятно, куда он перескакивает!
с точки зрения производительности (и зная, что Seq, вероятно, будет списком во время выполнения) будет лучше объединить оба Seqs или использовать flatten?