加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

在Scala中,如何以编程方式确定案例类的字段名称?

发布时间:2020-12-16 08:58:54 所属栏目:安全 来源:网络整理
导读:在 Scala中,假设我有一个这样的案例类: case class Sample(myInt: Int,myString: String) 有没有办法让我获得Seq [(String,Class [_])],或者更好的是,Seq [(String,Manifest)],描述case类的参数? 解决方法 这是我(两年后).这是使用Scala反射的不同的不同解
在 Scala中,假设我有一个这样的案例类:

case class Sample(myInt: Int,myString: String)

有没有办法让我获得Seq [(String,Class [_])],或者更好的是,Seq [(String,Manifest)],描述case类的参数?

解决方法

这是我(两年后).这是使用Scala反射的不同的不同解决方案.它的灵感来自 blog post,它本身的灵感来自于 Stack Overflow exchange.下面的解决方案专门针对上面原始海报的问题.

在一个编译单元(REPL:paste或编译的JAR)中,包括scala-reflect作为依赖项并编译以下内容(在Scala 2.11中测试,可能在Scala 2.10中有效):

import scala.language.experimental.macros 
import scala.reflect.macros.blackbox.Context

object CaseClassFieldsExtractor {
  implicit def makeExtractor[T]: CaseClassFieldsExtractor[T] =
    macro makeExtractorImpl[T]

  def makeExtractorImpl[T: c.WeakTypeTag](c: Context):
                              c.Expr[CaseClassFieldsExtractor[T]] = {
    import c.universe._
    val tpe = weakTypeOf[T]

    val fields = tpe.decls.collectFirst {
      case m: MethodSymbol if (m.isPrimaryConstructor) => m
    }.get.paramLists.head

    val extractParams = fields.map { field =>
      val name = field.asTerm.name
      val fieldName = name.decodedName.toString
      val NullaryMethodType(fieldType) = tpe.decl(name).typeSignature

      q"$fieldName -> ${fieldType.toString}"
    }

    c.Expr[CaseClassFieldsExtractor[T]](q"""
      new CaseClassFieldsExtractor[$tpe] {
        def get = Map(..$extractParams)
      }
    """)
  }
}

trait CaseClassFieldsExtractor[T] {
  def get: Map[String,String]
}

def caseClassFields[T : CaseClassFieldsExtractor] =
  implicitly[CaseClassFieldsExtractor[T]].get

在另一个编译单元(REPL中的下一行或使用前一个作为依赖项编译的代码)中,使用它如下:

scala> case class Something(x: Int,y: Double,z: String)
defined class Something

scala> caseClassFields[Something]
res0: Map[String,String] = Map(x -> Int,y -> Double,z -> String)

这似乎有点矫枉过正,但我??还是没能把它变得更短.这是它的作用:

> caseClassFields函数创建一个隐式存在的中间CaseClassFieldsExtractor,报告其发现并消失.
> CaseClassFieldsExtractor是一个带有伴随对象的特征,它使用宏来定义此特征的匿名具体子类.宏可以检查您的案例类的字段,因为它具有关于案例类的丰富的编译器级信息.
> CaseClassFieldsExtractor及其伴随对象必须在先前的编译单元中声明为检查您的案例类的那个,以便在您想要使用它时存在宏.
>您的案例类的类型数据通过WeakTypeTag传递.这将评估Scala结构,其中包含大量模式匹配,并且没有我能找到的文档.
>我们再次假设只有一个(“primary”?)构造函数,但我认为Scala中定义的所有类只能有一个构造函数.由于这种技术检查了构造函数的字段,而不是类中的所有JVM字段,所以它不容易因为缺乏一般性而损害了我以前的解决方案.
>它使用quasiquotes来构建CaseClassFieldsExtractor的匿名,具体子类.
>所有“隐式”业务都允许在函数调用(caseClassFields)中定义和包装宏,而不会在尚未定义时过早调用.

任何可以改进此解决方案的评论或解释“暗示”究竟如何做他们所做的事情(或者如果他们可以被删除)都是受欢迎的.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读