如何为自定义Scala集合(具有正确的方差)实现newBuilder? [英] How to implement newBuilder for a custom Scala collection (with correct variance)?

查看:965
本文介绍了如何为自定义Scala集合(具有正确的方差)实现newBuilder?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图实现一个新的集合类型,遵循与标准库相同的成语
,但我无法弄清楚如何处理
Builder 力学。我阅读了优秀的Scala架构
Collectionsdoc
page

,但它不能覆盖我的情况。



这是一个简化的版本'm试图做:

  import scala.collection.TraversableLike 
import scala。 (A,B),AsyncMap [A​​,B],A,B,B,B ]]
{

def empty:AsyncMap [A​​,B]

//这是与scala.collection.Map的主要区别(AsyncMap doesn' t
//块,同时检查它是否包含给定键的元素)。
def get(key:A):Future [Option [B]]

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

}

编译上述代码给我一个错误: / p>


 错误:覆盖方法newBuilder in trait TraversableLike类型=> 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)]]不兼容类型
trait AsyncMap [A​​,+ B]
^


我这是抱怨的是 GenericTraversableTemplate
有一个具体的 newBuilder 实现,其签名与
不兼容 TraversableLike 正在寻找。



实现 newBuilder:Builder [(A,B) Traversable [(A,B)]] 产生此
错误:


 code>错误:覆盖方法newBuilder in trait TraversableLike类型=> scala.collection.mutable.Builder [(A,B),AsyncMap [A​​,B]]; 
方法newBuilder类型不兼容
override def newBuilder:Builder [(A,B),Traversable [(A,B)]] = {
^


B]] 产生此
错误:


 错误:协变量类型B发生在类型=>中的逆变位置。方法newBuilder的$ scala.collection.mutable.Builder [(A,B),AsyncMap [A​​,B]] 
override def newBuilder:Builder [(A,B),AsyncMap [A​​,B]] = {
^


我想我在正确的轨道后面的方法,但不知道如何
指定这里的方差。



我也试图让这看起来更像是内部集合by
实现
trait AsyncMapLike [A,+ B,+ This< ;: AsyncMapLike [A,B,This] with AsyncMap [A​​,B]]
,但是这种方法没有产生任何结果。



我应该承认我对Scala很新,虽然我认为我理解它的
类型系统我可能不知道一些类型操作符或简单的设计模式
解决这个问题。



任何帮助将非常感激。 >




可能有关的问题:




解决方案

由于 mucaho 帮助我在上述评论中发现,结果是我的问题是由缺少访问修饰符。关于差异的错误消息仍然对我没有意义(我已经打开了一个关于它的新问题:为什么scalac只发出方差错误与某些访问修饰符?),但是当我覆盖 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]

//这样工作!
override protected [this] def newBuilder:Builder [(A,B),AsyncMap [A​​,B]] =?
}


I'm attempting to implement a new collection type which follows the same idioms as the standard library, but am having trouble figuring out how to handle the Builder mechanics. I've read through the excellent "Architecture of Scala Collections" doc page, but it doesn't cover my situation.

Here's a simplified version of what I'm trying to do:

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]

}

Compiling the above code gives me an error:

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]
      ^

I think what this is complaining about is that GenericTraversableTemplate has a concrete newBuilder implementation whose signature is incompatible with the one that TraversableLike is looking for. What I don't understand is how I can get around this.

Implementing newBuilder: Builder[(A, B), Traversable[(A, B)]] produces this error:

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)]] = {
               ^

While implementing newBuilder: Builder[(A, B), AsyncMap[A, B]] produces this error:

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]] = {
               ^

I think I'm on the right track with the latter approach, but am not sure how to specify the variance here.

I've also tried making this look more like the internal collections by implementing a trait AsyncMapLike[A, +B, +This <: AsyncMapLike[A, B, This] with AsyncMap[A, B]], but that approach hasn't borne any fruit.

I should admit that I'm pretty new to Scala and while I think I understand its type system I could be unaware of some type operator or simple design pattern that solves this.

Any help would be greatly appreciated.


Possibly-related questions:

解决方案

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?), but when I override newBuilder with a concrete implementation whose access is protected[this], everything works as expected (previously I had been trying to make it 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]] = ???
}

这篇关于如何为自定义Scala集合(具有正确的方差)实现newBuilder?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆