Как реализовать 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 и, хотя я думаю, что понимаю систему типов, я мог не знать о каком-либо операторе типов или простом шаблоне проектирования, который решает эту проблему.
Любая помощь будет принята с благодарностью.
Возможные вопросы:
- Создание типизированной коллекции
- Конкретный конструктор для параметризованного типа
- Наследование Скалы; Проблема строителя; Неуниверсальный IterableLike
- Как мне указать newBuilder для набора 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]] = ???
}