如何将此 SetLike 集合从 Scala 2.12 转换为 2.13?
Posted
技术标签:
【中文标题】如何将此 SetLike 集合从 Scala 2.12 转换为 2.13?【英文标题】:How to convert this SetLike collection from Scala 2.12 to 2.13? 【发布时间】:2021-06-21 11:33:41 【问题描述】:我有这个简单的不可变的基于 Long 的位集,其中包含 Card
案例类。不幸的是,随着 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
【问题讨论】:
【参考方案1】:应该是这样的;我已经评论了值得注意的步骤
// 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))
【讨论】:
以上是关于如何将此 SetLike 集合从 Scala 2.12 转换为 2.13?的主要内容,如果未能解决你的问题,请参考以下文章