代码之家  ›  专栏  ›  技术社区  ›  Georg Heiler

为案例类自动生成案例对象

  •  0
  • Georg Heiler  · 技术社区  · 7 年前

    如何让scala编译器自动生成case对象?

    // Pizza class
    class Pizza (val crust_type: String)
    
    // companion object
    object Pizza {
        val crustType = "crust_type"
    }
    

    case对象的所需属性

    • 对于中的每个属性 case class 在中生成属性 case object
    • camelCase snake_case 对于对象属性名,保留 蛇形箱 对象属性值
    1 回复  |  直到 7 年前
        1
  •  3
  •   Dmytro Mitin    7 年前

    可以创建宏注释

    import scala.annotation.{StaticAnnotation, compileTimeOnly}
    import scala.language.experimental.macros
    import scala.reflect.macros.blackbox
    
    @compileTimeOnly("enable macro paradise to expand macro annotations")
    class GenerateCompanion extends StaticAnnotation {
      def macroTransform(annottees: Any*): Any = macro GenerateCompanion.impl
    }
    
    object GenerateCompanion {
      def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
        import c.universe._
    
        annottees match {
          case (c@q"$_ class $tpname[..$_] $_(...$paramss) extends { ..$_ } with ..$_ { $_ => ..$_ }") :: Nil =>
    
            val vals = paramss.flatten.map(p => {
              val name = p.name.toString
              q"val ${TermName(underscoreToCamel(name))}: String = $name"
            })
    
            q"""
              $c
              object ${tpname.toTermName} {..$vals}
            """
        }
      }
    
      def underscoreToCamel(name: String): String = "_([a-z\\d])".r.replaceAllIn(name, _.group(1).toUpperCase)
    }
    

    使用它

    @GenerateCompanion
    class Pizza(val crust_type: String)
    
    Pizza.crustType //crust_type
    

    新宏:

    import scala.annotation.{StaticAnnotation, compileTimeOnly}
    import scala.language.experimental.macros
    import scala.reflect.macros.blackbox
    
    @compileTimeOnly("enable macro paradise to expand macro annotations")
    class GenerateCompanion extends StaticAnnotation {
      def macroTransform(annottees: Any*): Any = macro GenerateCompanion.impl
    }
    
    object GenerateCompanion {
      def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
        import c.universe._
    
        def vals(paramss: Seq[Seq[ValDef]]): Seq[ValDef] =
          paramss.flatten.map(p => {
            val name = p.name.toString
            q"val ${TermName(underscoreToCamel(name))}: String = $name"
          })
    
        annottees match {
          case (c@q"$_ class $tpname[..$_] $_(...$paramss) extends { ..$_ } with ..$_ { $_ => ..$_ }") :: Nil =>
            q"""
              $c
              object ${tpname.toTermName} {
                ..${vals(paramss)}
              }
              """
    
          case (c@q"$_ class $tpname[..$_] $_(...$paramss) extends { ..$_ } with ..$_ { $_ => ..$_ }") ::
            q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body }" :: Nil =>
            q"""
               $c
               $mods object $tname extends { ..$earlydefns } with ..$parents { $self =>
                ..$body
                ..${vals(paramss)}
               }
              """
        }
      }
    
      def underscoreToCamel(name: String): String = "_([a-z\\d])".r.replaceAllIn(name, _.group(1).toUpperCase)
    }
    

    用法:

    @GenerateCompanion
    class Pizza(val crust_type: String, val foo_foo: Int)
    
    object Pizza {
      def bar: String = "bar"
    }
    
    Pizza.crustType //crust_type
    Pizza.fooFoo //foo_foo
    Pizza.bar //bar
    
    推荐文章