如何将此 SetLike 集合从 Scala 2.12 转换为 2.13?

How to convert this SetLike collection from Scala 2.12 to 2.13?

我有这个简单的不可变的基于 Long 的位集,其中包含 Card 案例 class。不幸的是,随着 Scala 2.13 集合的改进,它不再编译了。

我看过 Scala 2.13 中的 BitSet 实现,但它非常冗长。我将如何在保持代码简洁明了的同时转换此 class?是否有我可以构建的此类数据结构的演示示例?

import scala.collection.{GenSet, GenTraversableOnce, SetLike}

case class Card(ord: Int)

case class Deck(data: Long) extends Set[Card] with SetLike[Card, Deck] {
    def iterator = new Iterator[Card] {
        var cur = data

        def next = {
            val res = java.lang.Long.numberOfTrailingZeros(cur)
            cur &= ~(1L << res)
            Card(res)
        }

        def hasNext = cur != 0
    }

    override def empty: Deck = Deck.empty
    override def size: Int = java.lang.Long.bitCount(data)
    override def contains(card: Card): Boolean = (data & (1L << card.ord)) > 0
    override def +(card: Card): Deck = Deck(data | (1L << card.ord))
    override def -(card: Card): Deck = Deck(data & ~(1L << card.ord))

    private def toBits(deck: GenTraversableOnce[Card]): Long = deck match {
        case deck: Deck => deck.data
        case _ =>
            var data = 0L
            for (card <- deck) data |= 1L << card.ord
            data
    }

    override def ++(deck: GenTraversableOnce[Card]): Deck = Deck(data | toBits(deck))
    override def &(deck: GenSet[Card]): Deck = Deck(data & toBits(deck))
    override def diff(deck: GenSet[Card]): Deck = Deck(data & ~toBits(deck))
}

object Deck {
    val empty: Deck = Deck(0)
    def of(deck: Iterable[Card]): Deck = empty ++ deck
}

应该是这样的;我评论了值得注意的步骤

// SetLike has been sorta superseded by SetOps. Notice the 3rd type parameter -
// that's the return constructor of e.g. deck.map(Some(_))
case class Deck(data: Long) extends Set[Card] with SetOps[Card, Set, Deck] {
  
  // Minimum definition of set is these two, instead of symbolic names
  override def incl(card: Card): Deck = Deck(data | (1L << card.ord))
  override def excl(card: Card): Deck = Deck(data & ~(1L << card.ord))

  def iterator = new Iterator[Card] {
    var cur = data

    def next() = {
      val res = java.lang.Long.numberOfTrailingZeros(cur)
      cur &= ~(1L << res)
      Card(res)
    }

    def hasNext = cur != 0
  }

  override def empty: Deck = Deck.empty
  override def size: Int = java.lang.Long.bitCount(data)
  override def contains(card: Card): Boolean = (data & (1L << card.ord)) > 0

  // These two are inherited from SetOps but neither their type nor the impl aligns with
  // what you want them to do. You have to re-override them to type as Deck instead of Set[Card]
  override protected def fromSpecific(coll: IterableOnce[Card]): Deck = Deck(toBits(coll))
  
  override protected def newSpecificBuilder: Builder[Card, Deck] =
    new Builder[Card, Deck] {
      var data = 0L
      def clear(): Unit = data = 0
      def result(): Deck = Deck(data)
      def addOne(elem: Card): this.type = {
        data |= (1L << elem.ord)
        this
      }
    }

  // I kept this as is but you can probably replace it with newSpecificBuilder
  // if you want to keep things more DRY - you could use
  // `newSpecificBuilder.addAll(deck).result()` in fromSpecific
  private def toBits(deck: IterableOnce[Card]): Long = deck match {
    case deck: Deck => deck.data
    case _ =>
      var data = 0L
      for (card <- deck.iterator) data |= 1L << card.ord
      data
  }

  
  // concat is the only non-final method - union and | just delegate to that.
  override def concat(deck: IterableOnce[Card]): Deck = Deck(data | toBits(deck))
  
  // this needs a set of unknown-mutability. It has kinda replaced GenSet
  override def diff(deck: scala.collection.Set[Card]): Deck = Deck(data & ~toBits(deck))
}