如何为自定义 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 个问题:
- Creating typed collection
- Specific Builder for Parameterized Type
- Scala Inheritance; Builder Trouble; Non-Generic IterableLike
- How do I specify a newBuilder for a scala set?
- Error: Covariant type A occurs in contravariant position
- covariant type T occurs in contravariant position
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]] = ???
}
我正在尝试实现一个遵循相同习语的新 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 个问题:
- Creating typed collection
- Specific Builder for Parameterized Type
- Scala Inheritance; Builder Trouble; Non-Generic IterableLike
- How do I specify a newBuilder for a scala set?
- Error: Covariant type A occurs in contravariant position
- covariant type T occurs in contravariant position
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]] = ???
}