是否可以使用鏡像甚至宏來區分 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
uj5u.com熱心網友回復:
你可以用<:<and做到NotGiven:
<:< reflect.Enum用于檢查您的型別是否是的子類scala.reflect.Enum(僅適用于 Scala 3enums)NotGiven將缺乏<:<證據轉化為false
以下是它的實作方式:
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]
uj5u.com熱心網友回復:
感謝@Ga?l J 的評論,這就是我的想法。不幸的是,它使用宏,但很簡單。
在一個檔案中:
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明確。
uj5u.com熱心網友回復:
感謝@Andrey Tyukin 和@Ga?l J,這是一個更簡單的版本。
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://www.uj5u.com/qukuanlian/366278.html
上一篇:將所有資料框列合并為一列作為JSON并保留JSON型別
下一篇:if陳述句,來回
