如何为自定义 Scala collection(具有正确的方差)实现 newBuilder?

How to implement newBuilder for a custom Scala collection (with correct variance)?

我正在尝试实现一个遵循相同习语的新 collection 类型 作为标准库,但我无法弄清楚如何处理 Builder 机械师。我已经通读了优秀的 "Architecture of 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]] = {
               ^

我认为我采用后一种方法是正确的,但我不确定如何 在此处指定方差。

我也试过让这个看起来更像内部 collections 实施一个 trait AsyncMapLike[A, +B, +This <: AsyncMapLike[A, B, This] with AsyncMap[A, B]], 但这种方法没有取得任何成果。

我应该承认我是 Scala 的新手,虽然我认为我理解它 类型系统 我可能不知道某些类型运算符或简单的设计模式 解决了这个问题。

如有任何帮助,我们将不胜感激。


Possibly-related 个问题:

As mucaho helped me discover in the comments above, it turns out that my problem was caused by a missing access modifier. The error message about variance still doesn't make sense to me (I've opened a new question about it: Why does scalac only emit variance errors with certain access modifiers?),但是当我用访问权限为 protected[this] 的具体实现重写 newBuilder 时,一切都按预期工作(之前我一直试图使它成为 public).

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]] = ???
}