微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

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

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

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))
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。