Scala 3带参数枚举为何引发values/valueOf序列化错误?
Scala 3枚举添加带参数Case后values/valueOf不可用的原因
问题场景
正常运行的Scala 3枚举代码
enum BrandSafetyFeatureStatus(val value: Long): case Inclusion extends BrandSafetyFeatureStatus(1L << 0) case Exclusion extends BrandSafetyFeatureStatus(1L << 1) case Exception extends BrandSafetyFeatureStatus(1L << 2) @main def main(): Unit = { println(BrandSafetyFeatureStatus.values) }
添加带参数Mixed case后的代码
enum BrandSafetyFeatureStatus(val value: Long): case Inclusion extends BrandSafetyFeatureStatus(1L << 0) case Exclusion extends BrandSafetyFeatureStatus(1L << 1) case Exception extends BrandSafetyFeatureStatus(1L << 2) private case Mixed(mixed: Long) extends BrandSafetyFeatureStatus(mixed) // ⚠️ // 位运算方法 def |(other: BrandSafetyFeatureStatus): BrandSafetyFeatureStatus = Mixed(value | other.value) def hasFlag(flag: BrandSafetyFeatureStatus): Boolean = (value & flag.value) == flag.value @main def main(): Unit = { println(BrandSafetyFeatureStatus.valueOf("X")) // 编译失败 println(BrandSafetyFeatureStatus.values) // 编译失败 }
编译错误信息
value values is not a member of object scala3.BrandSafetyFeatureStatus. Although class BrandSafetyFeatureStatus is an enum, it has non-singleton cases, meaning a values array is not defined
核心疑问
该现象是Scala 3的设计使然,还是未修复的开放Bug?
解答
这是Scala 3的设计特性,而非Bug。
Scala 3对枚举的values数组和valueOf方法有明确生成规则:只有当枚举的所有case都是无参数的单例对象时,编译器才会自动生成这两个成员。一旦枚举中存在带参数的case(比如示例中的Mixed(mixed: Long)),这类case可以创建任意多个实例,枚举不再是“有限固定实例的集合”——此时values无法涵盖所有可能的实例,valueOf也无法通过名称唯一确定实例,因此编译器不会生成这两个成员。
如果需要同时支持位运算混合状态和固定枚举实例的遍历/查找,可以使用enumeratum库实现:
sealed class BrandSafetyFeatureStatus(val value: Long) extends EnumEntry { def | (other: BrandSafetyFeatureStatus): BrandSafetyFeatureStatus = BrandSafetyFeatureStatus(value | other.value) def hasFlag(flag: BrandSafetyFeatureStatus): Boolean = (value & flag.value) == flag.value } object BrandSafetyFeatureStatus extends Enum[BrandSafetyFeatureStatus]: case object Inclusion extends BrandSafetyFeatureStatus(1L << 1) case object Exclusion extends BrandSafetyFeatureStatus(1L << 2) case object Exception extends BrandSafetyFeatureStatus(1L << 3) override def values: IndexedSeq[BrandSafetyFeatureStatus] = findValues @main def main(): Unit = { println(BrandSafetyFeatureStatus.withName("X")) println(BrandSafetyFeatureStatus.values) }
enumeratum通过手动定义单例case object并继承EnumEntry,明确区分了固定枚举实例和动态生成的混合状态,同时保留了遍历固定实例的values和查找固定实例的withName方法。
内容的提问来源于stack exchange,提问作者Zvi Mints
相关产品推荐
相关产品推荐

