簡體   English   中英

使用Scala反射獲取構造函數參數值

[英]Get constructor parameter values using scala reflection

使用scala在代碼庫中為某些類希望您定義某種“制作新版本”-例如,如果您有一個類x(a:int,b:String,c:double)。 。它具有如下功能:

class x( a: Integer, b : String, c : Double) extends CanMakeNew
{
    def newValue() = x( a, b, c)
}

我對此無能為力-但寧願不要每次都執行它。 或者,嗯...曾經。 在scala中,有沒有一種方法可以反射-迭代構造函數的參數值? 我可以使用反射來查看參數類型 -但由於尚未為該模塊打開參數名,因此無法打開它-我無法將它們與類中的存儲值相關聯。 從根本上講,我正在尋找實現以下特征的方法:

trait CanMakeNewDoneForMe extends CanMakeNew {
    def newValue()  {I need the code that goes here}

那么,scala反射是否可以通過任何方式檢查構造函數或檢查對象並看到“啊,這是構造函數中的第三個參數”?

如果將X case類,它將具有applycopy ...由編譯器自動生成。

基本上這不是我的代碼庫,因此我無法真正更改任何事物的形狀...

當您將一個類設為案例類時,您實際上並沒有“改變事物的形狀”,而只是添加了自動生成的方法。

無論如何,您可以創建一個生成方法newValue的宏注釋。

  import scala.annotation.StaticAnnotation
  import scala.language.experimental.macros
  import scala.reflect.macros.blackbox

  class newValue extends StaticAnnotation {
    def macroTransform(annottees: Any*): Any = macro newValueMacro.impl
  }

  object newValueMacro {
    def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
      import c.universe._
      annottees match {
        case q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }" :: tail =>
          val tparams1 = tparams.map {
            case q"$_ type $name[..$_] >: $_ <: $_" => tq"$name"
          }
          val paramss1 = paramss.map(_.map {
            case q"$_ val $pat: $_ = $_" => pat
          })
          q"""
              $mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self =>
                def newValue() = new $tpname[..$tparams1](...$paramss1)
                ..$stats
              }

              ..$tail
            """

        case _ => c.abort(c.enclosingPosition, "not a class")
      }

    }
  }

  @newValue
  /*case*/ class X(a: Int, b : String, c : Double) {
    override def toString: String = s"X($a, $b, $c)"
  }

  val x = new X(1, "a", 2.0) //X(1, a, 2.0)
  //  val x1 = x.copy()
  val x1 = x.newValue() //X(1, a, 2.0)

我在這里可能是錯的,但通常這是通過使用模式匹配以及在隨播對象中定義的apply()unapply()方法來實現的。

我已經在REPL會話中對您的上述代碼進行了小測試。 我不了解newvalue()函數的用途,因此我跳過了它。

class x(val a: Integer, val b : String, val c : Double)
{
  //def newValue() = x( a, b, c)
}

object x {
  def apply(a: Integer, b: String, c: Double): x = new x(a,b,c)
  def unapply(m: x): Option[(Integer, String, Double)] = Some((m.a, m.b, m.c))
}

x(1, "hello", 99.0d) match {
  case l: x => println(s"this the the 3rd arg in the constructor: ${l.c}")
}

上面的unapply()函數def允許對象上的模式匹配解構。 替代方法是使用case class來定義類x (這將為您定義apply()unapply()函數)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM