是否可以使用Mirrors甚至Macros来区分Scala-3枚举和密封特征?
transparent inline def isScalaEnum[A]: Boolean = ${ isScalaEnumImpl[A] }
private def isScalaEnumImpl[A: Type](using q: Quotes): Expr[Boolean] = ???例如,如何实现上述宏?
sealed trait T
case class A(x: Int) extends T
case class B(x: String) extends T
enum Color(val rgb: Int):
case Red extends Color(1)
case Green extends Color(2)
isScalaEnum[T] should be false
isScalaEnum[Color] should be true发布于 2021-11-17 22:52:27
你可以用<:<和NotGiven做到这一点
用于检查您的类型是否为false的子类的
<:< reflect.Enum (这仅适用于用于将缺少<:<-evidence转换为false的scala3 scala.reflect.Enum
下面是它的实现方式:
import scala.util.NotGiven
case class IsEnum[X](value: Boolean)
given isEnum[X](using X <:< reflect.Enum): IsEnum[X] = IsEnum(true)
given isNotEnum[X](using NotGiven[X <:< reflect.Enum]): IsEnum[X] = IsEnum(false)
inline def isScalaEnum[X](using inline ev: IsEnum[X]): Boolean = ev.value下面是它的使用方法:
enum Foo:
case Bar
sealed trait NotFoo
@main def demo(): Unit =
println(isScalaEnum[Foo]) // true
println(isScalaEnum[NotFoo]) // false更新
如果你想在编译时获得更精确的类型信息,只需透明地内联所有内容:
import scala.util.NotGiven
case class IsEnum[X](value: Boolean)
transparent inline given isEnum[X](using X <:< reflect.Enum): IsEnum[X] =
IsEnum(true)
transparent inline given isNotEnum[X](using NotGiven[X <:< reflect.Enum]): IsEnum[X] =
IsEnum(false)
transparent inline def isScalaEnum[X](using inline ev: IsEnum[X]): ev.value.type =
ev.value然后,它的行为类似于您在自己的答案中提到的测试用例,但Null和Nothing是值得注意的例外:
enum Foo:
case Bar
enum FooS(x:String):
case Bar extends FooS("str")
sealed trait NotFoo
inline val a: true = isScalaEnum[Foo]
inline val b: true = isScalaEnum[Foo.Bar.type]
inline val c: true = isScalaEnum[FooS]
inline val d: true = isScalaEnum[FooS.Bar.type]
inline val e: false = isScalaEnum[NotFoo]
inline val f: false = isScalaEnum[Int]
inline val g: false = isScalaEnum[String]
inline val x: true = isScalaEnum[Null]
inline val y: true = isScalaEnum[Nothing]发布于 2021-11-18 05:56:47
感谢@Ga的评论,这是我想出来的。不幸的是,它使用的是Macro,但很简单。
在一个文件中:
import scala.quoted.*
transparent inline def isScalaEnum[A]: Boolean =
${ isScalaEnumImpl[A] }
private def isScalaEnumImpl[A: Type](using q: Quotes): Expr[Boolean] =
import q.reflect.*
TypeRepr.of[A].asType match
case '[Null] => Expr(false) // Return false for Null, regardless of whether explicit-nulls are enabled.
case '[Nothing] => Expr(false) // I prefer false for Nothing
case '[reflect.Enum] => Expr(true)
case _ => Expr(false)以下是我的测试:
enum Foo:
case Bar
enum FooS(x:String):
case Bar extends FooS("str")
sealed trait NotFoo
@main
def demo(): Unit =
inline val a: true = isScalaEnum[Foo]
inline val b: true = isScalaEnum[Foo.Bar.type]
inline val c: true = isScalaEnum[FooS]
inline val d: true = isScalaEnum[FooS.Bar.type]
inline val e: false = isScalaEnum[NotFoo]
inline val f: false = isScalaEnum[Int]
inline val g: false = isScalaEnum[Null]
inline val h: false = isScalaEnum[Nothing]如果您认为有更简单/更好的解决方案,或者我在这里提供的内容有问题,请告诉我。
编辑:
多亏了@Andrey Tyukin注释/答案,我更改了宏以显式处理Null和Nothing。
发布于 2021-11-18 18:33:08
感谢@Andrey Tyukin和@Ga,这是一个更简单的版本。
transparent inline def isScalaEnum[X]: Boolean = inline compiletime.erasedValue[X] match
case _: Null => false // Return false for Null, regardless of whether explicit-nulls are enabled.
case _: Nothing => false // I prefer false for Nothing
case _: reflect.Enum => true
case _ => false以下是一些测试:
enum Foo:
case Bar
enum FooS(x:String):
case Bar extends FooS("str")
sealed trait NotFoo
inline val a: true = isScalaEnum[Foo]
inline val b: true = isScalaEnum[Foo.Bar.type]
inline val c: true = isScalaEnum[FooS]
inline val d: true = isScalaEnum[FooS.Bar.type]
inline val e: false = isScalaEnum[NotFoo]
inline val f: false = isScalaEnum[Int]
inline val g: false = isScalaEnum[String]
inline val x: false = isScalaEnum[Null]
inline val y: false = isScalaEnum[Nothing]https://stackoverflow.com/questions/70009589
复制相似问题