首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >scala 3宏:从宏返回Map[String,Class[Any]]

scala 3宏:从宏返回Map[String,Class[Any]]
EN

Stack Overflow用户
提问于 2021-01-24 11:06:47
回答 1查看 389关注 0票数 2

我正试图针对Scala3.0.0-M3编写一个宏。我希望宏返回类型的Option_字段的内部类型。例如,考虑到:

代码语言:javascript
复制
class Professor(val lastName: String, val id: Option[Int], val bossId: Option[Long])

我想把id和Int联系起来,把bossId和Long联系起来。

我有一些用于基本类型和编译ok的代码:

代码语言:javascript
复制
import scala.quoted._
import scala.quoted.staging._
import scala.quoted.{Quotes, Type}

object TypeInfo {


  inline def fieldsInfo[T <: AnyKind]: Map[String, Class[Any]] = ${ fieldsInfo[T] }

  def fieldsInfo[T <: AnyKind: Type](using qctx0: Quotes): Expr[Map[String, Class[Any]]] = {
    given qctx0.type = qctx0
    import qctx0.reflect.{given, _}

    val uns = TypeTree.of[T]
    val symbol = uns.symbol
    val innerClassOfOptionFields: Map[String, Class[Any]] = symbol.memberFields.flatMap { m =>
      // we only support val fields for now
      if(m.isValDef){
        val tpe = ValDef(m, None).tpt.tpe
        // only if the field is an Option[_]
        if(tpe.typeSymbol == TypeRepr.of[Option[Any]].typeSymbol){
          val containedClass: Option[Class[Any]] =
            if(tpe =:= TypeRepr.of[Option[Int]]) Some(classOf[Int].asInstanceOf[Class[Any]])
            else if(tpe =:= TypeRepr.of[Option[Short]])  Some(classOf[Short].asInstanceOf[Class[Any]])
            else if(tpe =:= TypeRepr.of[Option[Long]])  Some(classOf[Long].asInstanceOf[Class[Any]])
            else if(tpe =:= TypeRepr.of[Option[Double]])  Some(classOf[Double].asInstanceOf[Class[Any]])
            else if(tpe =:= TypeRepr.of[Option[Float]])  Some(classOf[Float].asInstanceOf[Class[Any]])
            else if(tpe =:= TypeRepr.of[Option[Boolean]])  Some(classOf[Boolean].asInstanceOf[Class[Any]])
            else if(tpe =:= TypeRepr.of[Option[Byte]])  Some(classOf[Byte].asInstanceOf[Class[Any]])
            else if(tpe =:= TypeRepr.of[Option[Char]])  Some(classOf[Char].asInstanceOf[Class[Any]])
            else None

          containedClass.map(clazz => (m.name -> clazz))
        } else None
      } else None
    }.toMap

    println(innerClassOfOptionFields)

    Expr(innerClassOfOptionFields)
  }

但如果我试着用它,像这样:

代码语言:javascript
复制
class Professor(val lastName: String, val id: Option[Int], val bossId: Option[Long])

object Main extends App {

  val fields = TypeInfo.fieldsInfo[Professor]

}

编译器首先打印Map(id -> int, bossId -> long),因为宏代码中的println看起来不错,但随后失败了:

代码语言:javascript
复制
[error] 16 |  val fields = TypeInfo.fieldsInfo[Professor]
[error]    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]    |               Found:    (classOf[Int] : Class[Int])
[error]    |               Required: Class[Any]
[error]    | This location contains code that was inlined from Main.scala:34

我做错什么了?我不应该能够从宏返回一个Map,还是不应该这样?

请注意,宏中的if/ can逻辑并不重要,问题可以归结为(其他一切都是相等的):

代码语言:javascript
复制
    val result: Map[String, Class[Any]] = Map(
      "bossId" -> classOf[scala.Long].asInstanceOf[Class[Any]],
      "id" -> classOf[scala.Int].asInstanceOf[Class[Any]]
    )
    Expr(result)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-24 21:06:05

您可以基于标准图书馆里的那个定义这个缺失给定。

代码语言:javascript
复制
import scala.quoted._

given ToExpr[Class[?]] with {                               
  def apply(x: Class[?])(using Quotes) = {
    import quotes.reflect._
    Ref(defn.Predef_classOf).appliedToType(TypeRepr.typeConstructorOf(x)).asExpr.asInstanceOf[Expr[Class[?]]]
  }
}

在Scala 3的下一个版本中,这应该不再是必要的了。标准库的给定实例也是https://github.com/lampepfl/dotty/pull/11206,用于Class[?]

然后,您可以返回一个类型良好的Map[String, Class[?]]

代码语言:javascript
复制
inline def fieldsInfo: Map[String, Class[?]] = ${ fieldsInfoMacro }

def fieldsInfoMacro(using Quotes): Expr[Map[String, Class[?]]] = {
  val result: Map[String, Class[?]] = Map(
    "bossId" -> classOf[scala.Long],
    "id" -> classOf[scala.Int]
  )
  Expr(result)
}

一切都正常:

代码语言:javascript
复制
scala> fieldsInfo                                                               
val res1: Map[String, Class[?]] = Map(bossId -> long, id -> int)
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65869784

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档