如何创建具有特定类型的 List 的包装器

发布于 2024-11-01 05:07:04 字数 1372 浏览 5 评论 0原文

我正在尝试创建具有特定类型(例如 List[Int])的 List 包装器,以便采用隐式 CanBuildFrom 参数的方法返回我的包装器的实例而不是 List

一种可能的解决方案(感觉相当重量级)是:

import scala.collection._
import generic.{CanBuildFrom, SeqForwarder}
import mutable.{Builder, ListBuffer}

class MyList(list: List[Int]) extends immutable.LinearSeq[Int]
                                 with LinearSeqLike[Int, MyList]
                                 with SeqForwarder[Int] {
  override def newBuilder: Builder[Int, MyList] = MyList.newBuilder
  protected override def underlying = list
}

object MyList {
  def newBuilder: Builder[Int, MyList] =
    new ListBuffer[Int] mapResult(new MyList(_))

  implicit def canBuildFrom: CanBuildFrom[MyList, Int, MyList] = {
    new CanBuildFrom[MyList, Int, MyList] {
      def apply(from: MyList) = from.newBuilder
      def apply() = newBuilder
    }
  }
}

val l1 = new MyList(List(1,2,3))

println(l1.isInstanceOf[MyList])
println(l1.map(_ + 1).isInstanceOf[MyList])
println(l1.filter(_ == 2).isInstanceOf[MyList])

是否有更好/更简单的方法来创建这样的包装器,或者我是否错过了 MyList 实现中的任何重要内容?

编辑:后续问题是:是否可以将整个包装器逻辑放入 ListWrapper 类或特征中,以便可以实现上述 MyList像这样:

class MyList extends ListWrapper[Int, MyList]

object MyList extends ListWrapperFactory[Int, MyList]

I am trying to create a wrapper of List with a specific type (e.g. List[Int]) such that methods that take an implicit CanBuildFrom parameter return an instance of my wrapper instead of List.

One possible solution, which feels rather heavyweight, is:

import scala.collection._
import generic.{CanBuildFrom, SeqForwarder}
import mutable.{Builder, ListBuffer}

class MyList(list: List[Int]) extends immutable.LinearSeq[Int]
                                 with LinearSeqLike[Int, MyList]
                                 with SeqForwarder[Int] {
  override def newBuilder: Builder[Int, MyList] = MyList.newBuilder
  protected override def underlying = list
}

object MyList {
  def newBuilder: Builder[Int, MyList] =
    new ListBuffer[Int] mapResult(new MyList(_))

  implicit def canBuildFrom: CanBuildFrom[MyList, Int, MyList] = {
    new CanBuildFrom[MyList, Int, MyList] {
      def apply(from: MyList) = from.newBuilder
      def apply() = newBuilder
    }
  }
}

val l1 = new MyList(List(1,2,3))

println(l1.isInstanceOf[MyList])
println(l1.map(_ + 1).isInstanceOf[MyList])
println(l1.filter(_ == 2).isInstanceOf[MyList])

Is there a better/easier way to create such a wrapper or did I miss anything important in the implementation of MyList?

Edit: A follow-up question is: Can this whole wrapper logic be put into ListWrapper classes or traits so that the above MyList can be implemented like this:

class MyList extends ListWrapper[Int, MyList]

object MyList extends ListWrapperFactory[Int, MyList]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

千柳 2024-11-08 05:07:04

据我阅读这篇文章所知:

http:// /www.scala-lang.org/docu/files/collections-api/collections-impl.html

如果您想要过滤器/地图/等,您的解决方案是最简单的。到 MyList 的所有返回实例。 filter 等操作需要 newBuilder,而 map 等操作需要隐式 CanBuildFrom,这可能会更改集合类型。

您在 CanBuildFrom 中应该做的是:

def apply(from: MyList) = from.newBuilder // call it on `from'

确保静态类型 MyList 上的 map 实际上具有动态类型是 MyList 的子类型将重用相同的动态类型。

编辑:似乎缺少一些东西,因为此 map 返回 List 的实例,而不是 MyList

val l1: LinearSeq[Int] = new MyList(List(1, 2, 3))
println(l1.map(_ + 1)) // prints List(2, 3, 4)

看起来链接文章中的 RNA 示例也是如此。如果它具有静态类型 IndexedSeq[Base] 而不是 RNA,则其上的 map 返回一个向量。

编辑2:看起来这是一个更普遍的问题,在这个问题中讨论。

As far I know from reading this article:

http://www.scala-lang.org/docu/files/collections-api/collections-impl.html

your solution is the simplest one, if you want filter/map/etc. to all return instances of MyList. newBuilder is needed for ops like filter, and the implicit CanBuildFrom for ops like map, which may change the collection type.

What you should maybe do in your CanBuildFrom is this:

def apply(from: MyList) = from.newBuilder // call it on `from'

which ensures that a map on a statically-typed MyList which actually has a dynamic type that is a subtype of MyList will reuse that same dynamic type.

Edit: seems like there is a little something missing, for this map returns an instance of List and not MyList:

val l1: LinearSeq[Int] = new MyList(List(1, 2, 3))
println(l1.map(_ + 1)) // prints List(2, 3, 4)

it looks like this is also the case with the RNA example taken from the linked article. If it has static type IndexedSeq[Base] instead of RNA, a map on it returns a vector.

Edit 2: looks like this is a more general problem, discussed in this question.

影子的影子 2024-11-08 05:07:04

关于我的后续问题如何通过类或特征混合包装器逻辑,这就是我想到的:

import scala.collection._

trait ListWrapper[Elem, Repr <: ListWrapper[Elem, Repr]]
    extends immutable.LinearSeq[Elem]
    with LinearSeqLike[Elem, Repr]
    with generic.SeqForwarder[Elem] { self: Repr =>

  def wrapperCompanion: ListWrapperCompanion[Elem, Repr]

  override def newBuilder: mutable.Builder[Elem, Repr] =
    wrapperCompanion.newBuilder
}

trait ListWrapperCompanion[Elem, Repr <: ListWrapper[Elem, Repr]] {
  def apply(elems: TraversableOnce[Elem]): Repr

  def newBuilder: mutable.Builder[Elem, Repr] =
    new mutable.ListBuffer[Elem].mapResult(apply)

  def canBuildFromWrapper: generic.CanBuildFrom[Repr, Elem, Repr] = {
    new generic.CanBuildFrom[Repr, Elem, Repr] {
      def apply(from: Repr) = from.newBuilder
      def apply() = newBuilder
    }
  }
}

现在 MyList 可以通过以下方式实现:

class MyList(val underlying: List[Int]) extends ListWrapper[Int, MyList] {
  def wrapperCompanion = MyList
}

object MyList extends ListWrapperCompanion[Int, MyList] {
  def apply(elems: TraversableOnce[Int]) = new MyList(elems.toList)

  implicit def canBuildFrom = canBuildFromWrapper
}

这绝对比将所有样板代码放在其中要好MyList 的定义,但是要使 MyList 成为 List 的包装器,仍然需要编写很多代码。

Regarding my follow-up question how to mixin the wrapper logic via classes or traits, this is what I came up with:

import scala.collection._

trait ListWrapper[Elem, Repr <: ListWrapper[Elem, Repr]]
    extends immutable.LinearSeq[Elem]
    with LinearSeqLike[Elem, Repr]
    with generic.SeqForwarder[Elem] { self: Repr =>

  def wrapperCompanion: ListWrapperCompanion[Elem, Repr]

  override def newBuilder: mutable.Builder[Elem, Repr] =
    wrapperCompanion.newBuilder
}

trait ListWrapperCompanion[Elem, Repr <: ListWrapper[Elem, Repr]] {
  def apply(elems: TraversableOnce[Elem]): Repr

  def newBuilder: mutable.Builder[Elem, Repr] =
    new mutable.ListBuffer[Elem].mapResult(apply)

  def canBuildFromWrapper: generic.CanBuildFrom[Repr, Elem, Repr] = {
    new generic.CanBuildFrom[Repr, Elem, Repr] {
      def apply(from: Repr) = from.newBuilder
      def apply() = newBuilder
    }
  }
}

Now MyList can be implemented by:

class MyList(val underlying: List[Int]) extends ListWrapper[Int, MyList] {
  def wrapperCompanion = MyList
}

object MyList extends ListWrapperCompanion[Int, MyList] {
  def apply(elems: TraversableOnce[Int]) = new MyList(elems.toList)

  implicit def canBuildFrom = canBuildFromWrapper
}

This is definitely better than having all the boilerplate code in MyList's definition, but it is still a lot to write for making MyList just a wrapper for List.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文