如何在使用 ClassTag 时覆盖 scala SeqFactory

问题描述 投票:0回答:1

我正在从这段代码片段中学习https://gist.github.com/tiqwab/bc8d372ca489a74b72dd2357e7d6b010创建一个自定义的scala Seq类。

package com.tiqwab.example.step4

import scala.collection.mutable.ListBuffer
import scala.collection.{immutable, mutable, SeqFactory, StrictOptimizedLinearSeqOps}

class MyList[+A: ClassTag] private (elems: List[A])
  extends immutable.LinearSeq[A] with immutable.LinearSeqOps[A, MyList, MyList[A]]
  with StrictOptimizedLinearSeqOps[A, MyList, MyList[A]] {
  // To be overridden in implementations, as said in scala.collection.LinearSeq
  override def isEmpty: Boolean = elems.isEmpty
  override def head: A = elems.head
  override def tail: MyList[A] = new MyList(elems.tail)

  override def iterator: Iterator[A] = elems.iterator

  // To be overridden for LinearSeqOps
  override def iterableFactory: SeqFactory[MyList] = MyList

  override def toString: String = s"MyList(${elems.mkString(",")})"
}

object MyList extends SeqFactory[MyList] {
  override def from[A](source: IterableOnce[A]): MyList[A] =
    newBuilder[A].addAll(source).result()
  override def empty[A]: MyList[A] =
    new MyList(List.empty)
  override def newBuilder[A]: mutable.Builder[A, MyList[A]] =
    new ListBuffer[A].mapResult(elems => new MyList(elems))
}

问题是如何将 ClassTag 附加到类型参数 A,如果我真的将标签附加到它,我将无法再重写 SeqFactory 中的方法。因为方法签名与 SeqFactory 中的方法签名不再一致。或者有更好的方法来使用类标签实现此类自定义集合吗?

package com.tiqwab.example.step4

import scala.collection.mutable.ListBuffer
import scala.collection.{immutable, mutable, SeqFactory, StrictOptimizedLinearSeqOps}

class MyList[+A] private (elems: List[A])
  extends immutable.LinearSeq[A] with immutable.LinearSeqOps[A, MyList, MyList[A]]
  with StrictOptimizedLinearSeqOps[A, MyList, MyList[A]] {
  // To be overridden in implementations, as said in scala.collection.LinearSeq
  override def isEmpty: Boolean = elems.isEmpty
  override def head: A = elems.head
  override def tail: MyList[A] = new MyList(elems.tail)

  override def iterator: Iterator[A] = elems.iterator

  // To be overridden for LinearSeqOps
  override def iterableFactory: SeqFactory[MyList] = MyList

  override def toString: String = s"MyList(${elems.mkString(",")})"
}

object MyList extends SeqFactory[MyList] {
  override def from[A: ClassTag](source: IterableOnce[A]): MyList[A] =
    newBuilder[A].addAll(source).result()
  override def empty[A: ClassTag]: MyList[A] =
    new MyList(List.empty)
  override def newBuilder[A: ClassTag]: mutable.Builder[A, MyList[A]] =
    new ListBuffer[A].mapResult(elems => new MyList(elems))
}
scala
1个回答
0
投票

你必须修改工厂,这样它就不会是一个

object
而是一个带有构造函数的类,然后将
ClassTag
传递到那里:

class MyListFactory[A: ClassTag] {
  override def from[A](source: IterableOnce[A]): MyList[A] =
    newBuilder[A].addAll(source).result()
  override def empty[A]: MyList[A] =
    new MyList(List.empty)
  override def newBuilder[A]: mutable.Builder[A, MyList[A]] =
    new ListBuffer[A].mapResult(elems => new MyList(elems))
}

object MyList {

  // one way of creating this things
  def apply[A: ClassTag]: MyListFactory[A] = new MyListFactory[A]

  // another way, requires enabling implicit conversions
  implicit def convertToFactory[A: ClassTag](
    notUsed: MyList.type // maybe add some @unused annotation here
  ): MyListFactory[A] = new MyListFactory[A]
}

您还可以看看 stdlib 是如何实现的,例如

SortedSet
,因为它需要
Ordering[A]

© www.soinside.com 2019 - 2024. All rights reserved.