Java 反射
如果您将 enum 声明为与 Java 兼容,则可以使用 Java 反射通过 Class.getEnumConstants 方法获取其值的数组。
要声明Java-compatible enum,它必须扩展Enum 类:
enum Color extends Enum[Color]:
case Red, Green, Blue
您可以在静态类上使用getEnumConstants 来正确键入Array 的值:
val values: Array[Color] = classOf[Color].getEnumConstants
但如果您想以通用方式使用它,我相信您必须使用asInstanceOf 将Class 或Array 转换为正确的类型:
def enumValues[E <: Enum[E] : ClassTag]: Array[E] =
classTag[E].runtimeClass.getEnumConstants.asInstanceOf[Array[E]]
子类型声明<: Enum[E] 不是严格需要的,但用于避免使用不相关的类调用它并导致运行时异常。
现在可以用类似的方式编写方法enumDescr:
def enumDescr[E <: Enum[E] : ClassTag]: String =
val cl = classTag[E].runtimeClass.asInstanceOf[Class[E]]
s"${cl.getName}: ${cl.getEnumConstants.mkString(", ")}"
并像这样调用:
scala> enumDescr[Color]
val res0: String = Color: Red, Green, Blue
Scala 编译时反射
如果您只想要枚举案例的名称,您可以使用scala.deriving.Mirror 获取它们(感谢@unclebob 的想法):
import scala.deriving.Mirror
import scala.compiletime.{constValue, constValueTuple}
enum Color:
case Red, Green, Blue
inline def enumDescription[E](using m: Mirror.SumOf[E]): String =
val name = constValue[m.MirroredLabel]
val values = constValueTuple[m.MirroredElemLabels].productIterator.mkString(", ")
s"$name: $values"
@main def run: Unit =
println(enumDescription[Color])
打印出来:
Color: Red, Green, Blue
用于值序列的 Scala 3 宏
您可以使用 Scala 3 宏在伴随对象上生成对 values 的调用。
无法调用来自同一文件的宏定义,因此必须将宏放在单独的文件中:
/* EnumValues.scala */
import scala.quoted.*
inline def enumValues[E]: Array[E] = ${enumValuesImpl[E]}
def enumValuesImpl[E: Type](using Quotes): Expr[Array[E]] =
import quotes.reflect.*
val companion = Ref(TypeTree.of[E].symbol.companionModule)
Select.unique(companion, "values").asExprOf[Array[E]]
然后在主文件中:
enum Color:
case Red, Green, Blue
// Usable from `inline` methods:
inline def genericMethodTest[E]: String =
enumValues[E].mkString(", ")
@main def run: Unit =
println(enumValues[Color].toSeq)
println(genericMethodTest[Color])