Как реализовать newBuilder для пользовательской коллекции Scala (с правильной дисперсией)?

Я пытаюсь реализовать новый тип коллекции, который следует тем же идиомам, что и стандартная библиотека, но у меня возникают проблемы с выяснением, как обращаться с Builder механика. Я прочитал отличную страницу документации "Архитектура Scala Collections", но она не охватывает мою ситуацию.

Вот упрощенная версия того, что я пытаюсь сделать:

import scala.collection.TraversableLike
import scala.concurrent.Future

trait AsyncMap[A, +B]
  extends Traversable[(A, B)]
  with TraversableLike[(A, B), AsyncMap[A, B]]
{

  def empty: AsyncMap[A, B]

  // This is the main difference from scala.collection.Map (an AsyncMap doesn't
  // block while it checks if it contains an element for a given key).
  def get(key: A): Future[Option[B]]

  def +[B1 >: B](kv: (A, B1)): AsyncMap[A, B1]

}

Компиляция приведенного выше кода дает мне ошибку:

error: overriding method newBuilder in trait TraversableLike of type => scala.collection.mutable.Builder[(A, B),AsyncMap[A,B]];
 method newBuilder in trait GenericTraversableTemplate of type => scala.collection.mutable.Builder[(A, B),Traversable[(A, B)]] has incompatible type
trait AsyncMap[A, +B]
      ^

Я думаю, что это жалуется на то, что GenericTraversableTemplate имеет бетон newBuilder реализация, чья подпись несовместима с той, что TraversableLike ищет. То, что я не понимаю, как я могу обойти это.

Внедрение newBuilder: Builder[(A, B), Traversable[(A, B)]] выдает эту ошибку:

error: overriding method newBuilder in trait TraversableLike of type => scala.collection.mutable.Builder[(A, B),AsyncMap[A,B]];
 method newBuilder has incompatible type
  override def newBuilder: Builder[(A, B), Traversable[(A, B)]] = {
               ^

При осуществлении newBuilder: Builder[(A, B), AsyncMap[A, B]] выдает эту ошибку:

error: covariant type B occurs in contravariant position in type => scala.collection.mutable.Builder[(A, B),AsyncMap[A,B]] of method newBuilder
  override def newBuilder: Builder[(A, B), AsyncMap[A, B]] = {
               ^

Я думаю, что я на правильном пути с последним подходом, но я не уверен, как указать здесь дисперсию.

Я также попытался сделать это больше похоже на внутренние коллекции путем реализации trait AsyncMapLike[A, +B, +This <: AsyncMapLike[A, B, This] with AsyncMap[A, B]] Но такой подход не принес никаких результатов.

Я должен признать, что я довольно новичок в Scala и, хотя я думаю, что понимаю систему типов, я мог не знать о каком-либо операторе типов или простом шаблоне проектирования, который решает эту проблему.

Любая помощь будет принята с благодарностью.


Возможные вопросы:

1 ответ

Решение

Поскольку mucaho помог мне обнаружить в комментариях выше, оказалось, что моя проблема была вызвана отсутствующим модификатором доступа. Сообщение об ошибке о дисперсии все еще не имеет смысла для меня (я открыл новый вопрос по этому поводу: почему скалак только генерирует ошибки дисперсии с определенными модификаторами доступа?), Но когда я переопределяю newBuilder с конкретной реализацией, доступ к которой protected[this]все работает как положено (ранее я пытался сделать это публично).

import scala.collection.mutable.Builder
import scala.collection.TraversableLike
import scala.concurrent.Future

trait AsyncMap[A, +B]
  extends Traversable[(A, B)]
  with TraversableLike[(A, B), AsyncMap[A, B]]
{
  def empty: AsyncMap[A, B]

  def get(key: A): Future[Option[B]]

  def +[B1 >: B](kv: (A, B1)): AsyncMap[A, B1]

  // This works!
  override protected[this] def newBuilder: Builder[(A, B), AsyncMap[A, B]] = ???
}
Другие вопросы по тегам