pme*_*pme 9 enums scala scala-3
我想要enumDescr
为任何 Scala 3 枚举提供一个简单的函数。
例子:
@description(enumDescr(InvoiceCategory))
enum InvoiceCategory:
case `Travel Expenses`
case Misc
case `Software License Costs`
Run Code Online (Sandbox Code Playgroud)
在Scala 2中这很简单 ( Enumeration
):
def enumDescr(enum: Enumeration): String =
s"$enum: ${enum.values.mkString(", ")}"
Run Code Online (Sandbox Code Playgroud)
但是Scala 3中是如何完成的:
def enumDescr(enumeration: ??) = ...
Run Code Online (Sandbox Code Playgroud)
Kol*_*mar 11
如果您将其声明enum
为与 Java 兼容,则可以使用 Java 反射来使用该方法获取其值的数组Class.getEnumConstants
。
要声明Java 兼容,enum
它必须扩展该类Enum
:
enum Color extends Enum[Color]:
case Red, Green, Blue
Run Code Online (Sandbox Code Playgroud)
getEnumConstants
您可以在静态类上使用来获取正确类型Array
的值:
val values: Array[Color] = classOf[Color].getEnumConstants
Run Code Online (Sandbox Code Playgroud)
但如果您想以通用方式使用它,我相信您必须使用以下命令将 theClass
或 the转换Array
为正确的类型asInstanceOf
:
def enumValues[E <: Enum[E] : ClassTag]: Array[E] =
classTag[E].runtimeClass.getEnumConstants.asInstanceOf[Array[E]]
Run Code Online (Sandbox Code Playgroud)
那里并不严格需要子类型声明<: Enum[E]
,但用于避免使用不相关的类调用它并导致运行时异常。
enumDescr
现在可以用类似的方式编写一个方法:
def enumDescr[E <: Enum[E] : ClassTag]: String =
val cl = classTag[E].runtimeClass.asInstanceOf[Class[E]]
s"${cl.getName}: ${cl.getEnumConstants.mkString(", ")}"
Run Code Online (Sandbox Code Playgroud)
并这样调用:
scala> enumDescr[Color]
val res0: String = Color: Red, Green, Blue
Run Code Online (Sandbox Code Playgroud)
如果您只想要枚举案例的名称,您可以使用它们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])
Run Code Online (Sandbox Code Playgroud)
这打印:
Color: Red, Green, Blue
Run Code Online (Sandbox Code Playgroud)
values
您可以使用 Scala 3 宏生成对伴生对象的调用。
无法调用同一文件中的宏定义,因此必须将宏放置在单独的文件中:
/* 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]]
Run Code Online (Sandbox Code Playgroud)
然后在主文件中:
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])
Run Code Online (Sandbox Code Playgroud)
我没有看到所有enum
伴生对象有任何共同特征。
不过,您仍然可以values
反射性地调用:
import reflect.Selectable.reflectiveSelectable
def descrEnum(e: { def values: Array[?] }) = e.values.mkString(",")
enum Foo:
case Bar
case Baz
descrEnum(Foo) // "Bar,Baz"
Run Code Online (Sandbox Code Playgroud)