如何实现编译时校验Map包含指定枚举的所有case作为键
实现方案
这类要求覆盖所有枚举键的映射结构通常被称为完备枚举映射(Total Enum Map),Scala生态下有多种实现方式可以满足编译期校验的要求:
方式1:Scala 3 原生实现(无第三方依赖)
通过inline+编译期反射可以直接实现轻量的校验逻辑,代码如下:
首先定义完备映射类型:
import scala.deriving.Mirror import scala.compiletime.* // 封装类,代理普通Map的所有能力 final class TotalEnumMap[K <: Enum[K], V] private (val inner: Map[K, V]) extends AnyVal: // 直接转发所有Map的原生方法,使用体验和普通Map完全一致 export inner.* object TotalEnumMap: inline def apply[K <: Enum[K], V](entries: (K, V)*)(using m: Mirror.SumOf[K]): TotalEnumMap[K, V] = val allEnumCount = constValue[m.MirroredElemLabels].size val inputKeys = entries.map(_._1).toSet // 编译期校验:传入的键数量必须等于枚举值总数,且无重复 if inputKeys.size != allEnumCount then error(s"枚举键覆盖不完整:当前仅传入${inputKeys.size}个键,需要覆盖全部${allEnumCount}个枚举值") new TotalEnumMap(Map(entries*))
使用示例:
// 编译报错,错误提示:枚举键覆盖不完整:当前仅传入3个键,需要覆盖全部4个枚举值 val invalidMap = TotalEnumMap( Connector.CHAdeMO -> 1, Connector.Mennekes -> 2, Connector.CCS -> 3, ) // 编译通过 val validMap = TotalEnumMap( Connector.CHAdeMO -> 1, Connector.Mennekes -> 2, Connector.CCS -> 3, Connector.Tesla -> 4 ) // 正常使用普通Map的所有方法 validMap(Connector.Tesla) // 返回4 validMap.get(Connector.CHAdeMO) // 返回Some(1) validMap.contains(Connector.Mennekes) // 返回true
方式2:第三方库实现
如果项目允许引入第三方依赖,Shapeless的异构映射、Cats的Total类型类都有现成的完备映射实现,无需自行编写校验逻辑。
内容的提问来源于stack exchange,提问作者Simão Martins
相关产品推荐
相关产品推荐

