Scala 3中如何合并ADT枚举集合内同类型统计项?
Scala 3枚举ADTs合并同类型统计项方案
首先先把你的Stats枚举定义好(假设是数值型统计项,合并逻辑为求和):
enum Stats: case MaximumHealth(value: Int) case HealthRegen(value: Int)
要实现同类型统计项合并,核心就是按枚举case分组,忽略参数值,然后对每组内的实例做数值合并。
步骤1:按枚举case分组
Scala 3的枚举实例自带enumCase方法,它会返回该实例对应的枚举case单例对象——同一个case的所有实例,enumCase是完全相同的,刚好可以作为分组的key:
val stats = Array(Stats.MaximumHealth(20), Stats.MaximumHealth(10), Stats.HealthRegen(5)) // 按枚举case分组,得到Map[EnumCase, Array[Stats]] val groupedStats = stats.groupBy(_.enumCase)
步骤2:合并每组内的统计项
接下来给每组写合并逻辑,用模式匹配处理不同case的求和:
先写一个通用的合并函数,处理同类型统计项的累加:
def mergeSameTypeStats(items: Iterable[Stats]): Stats = items match { // 从第一个元素开始,依次和后面的元素合并 case head :: tail => tail.foldLeft(head) { (acc, curr) => (acc, curr) match { case (Stats.MaximumHealth(a), Stats.MaximumHealth(b)) => Stats.MaximumHealth(a + b) case (Stats.HealthRegen(a), Stats.HealthRegen(b)) => Stats.HealthRegen(a + b) case _ => throw new IllegalArgumentException("不能合并不同类型的统计项") } } case Nil => throw new IllegalArgumentException("没有可合并的统计项") }
然后用这个函数处理每个分组,再转成数组:
val mergedStats = groupedStats.values.map(mergeSameTypeStats).toArray // 输出:Array(MaximumHealth(30), HealthRegen(5))
更优雅的写法(给枚举加合并方法)
如果想让代码更内聚,可以给每个枚举case单独定义合并方法:
enum Stats: case MaximumHealth(value: Int) extends Stats: def merge(other: MaximumHealth): MaximumHealth = MaximumHealth(this.value + other.value) case HealthRegen(value: Int) extends Stats: def merge(other: HealthRegen): HealthRegen = HealthRegen(this.value + other.value)
然后分组合并时用reduce:
val mergedStats = groupedStats.values.map { items => items.reduce { (a, b) => (a, b) match { case (mh1: Stats.MaximumHealth, mh2: Stats.MaximumHealth) => mh1.merge(mh2) case (hr1: Stats.HealthRegen, hr2: Stats.HealthRegen) => hr1.merge(hr2) case _ => throw new IllegalArgumentException("类型不匹配") } } }.toArray
注意点
- 如果你不想用
enumCase,也可以用_.productPrefix(返回枚举case的名称字符串,比如"MaximumHealth"),但enumCase是类型安全的,更推荐。 - 合并逻辑可以根据需求调整,比如不是求和而是取最大值,只需要修改对应case的合并代码即可。
内容的提问来源于stack exchange,提问作者user426445
相关产品推荐
相关产品推荐

