복붙노트

[SCALA] 어떻게 스칼라 반사를 통해 기본 매개 변수 값에 액세스합니까?

SCALA

어떻게 스칼라 반사를 통해 기본 매개 변수 값에 액세스합니까?

하자가 I 클래스가 있다고 가정 :

case class Foo(id: Int, name: String, note: Option[String] = None)

생성자와이 자동으로 생성 동반자 객체의 방법을 적용 모두 세 개의 매개 변수를. 반사를 통해 볼 때, 세번째 파라미터 (참고) 네요 :

p.isParamWithDefault = true

또한, 검사를 통해서 나는 동반자 객체의 값을 생성하는 방법을 찾을 수 있습니다 :

method <init>$default$3

method apply$default$3

어떤 두도 있습니다 :

m.isParamWithDefault = true

즉 실제로 위의 MethodSymbols의 기본 값도 아무것도 얻을 수있는 권리 방법 저 포인트 매개 변수 그러나, 나는 둘 다 노트에 대한 TermSymbol에 아무것도 찾을 수없는 매개 변수의 TermSymbol에 포인트 다시 그.

기본 값을 생성하는 방법과 매개 변수에 대한 TermSymbol을 연결하는 직선 전달 방법이 있나요? 아니면 내가 뭔가 kludgey을처럼 동반자 개체의 방법의 이름을 검사해야합니까?

난 둘 다 내가 여기있을 경우 클래스 생성자의 예를 들어 정기적 방법이에 관심이 있어요.

해결법

  1. ==============================

    1.kludge의 정도가있다.

    kludge의 정도가있다.

    이 답변에서 샘플 코드는 아래에 붙여 넣기.

    내가 말한 있도록, 이름의 형태는 4.6 사양에 6.6.1이다. 즉 임시 없습니다. 기본 인수 모든 파라미터 PI, J위한 방법 $ 기본 $ f를 N이라는 기본 인자를 계산하는 식으로 생성된다.

    액세스 및 재구성이 생성 된 이름으로 구조화 능력의 부족합니다 (ML에 현재 스레드) 알려진 문제입니다.

    import reflect._
    import scala.reflect.runtime.{ currentMirror => cm }
    import scala.reflect.runtime.universe._
    
    // case class instance with default args
    
    // Persons entering this site must be 18 or older, so assume that
    case class Person(name: String, age: Int = 18) {
      require(age >= 18)
    }
    
    object Test extends App {
    
      // Person may have some default args, or not.
      // normally, must Person(name = "Guy")
      // we will Person(null, 18)
      def newCase[A]()(implicit t: ClassTag[A]): A = {
        val claas = cm classSymbol t.runtimeClass
        val modul = claas.companionSymbol.asModule
        val im = cm reflect (cm reflectModule modul).instance
        defaut[A](im, "apply")
      }
    
      def defaut[A](im: InstanceMirror, name: String): A = {
        val at = newTermName(name)
        val ts = im.symbol.typeSignature
        val method = (ts member at).asMethod
    
        // either defarg or default val for type of p
        def valueFor(p: Symbol, i: Int): Any = {
          val defarg = ts member newTermName(s"$name$$default$$${i+1}")
          if (defarg != NoSymbol) {
            println(s"default $defarg")
            (im reflectMethod defarg.asMethod)()
          } else {
            println(s"def val for $p")
            p.typeSignature match {
              case t if t =:= typeOf[String] => null
              case t if t =:= typeOf[Int]    => 0
              case x                         => throw new IllegalArgumentException(x.toString)
            }
          }
        }
        val args = (for (ps <- method.paramss; p <- ps) yield p).zipWithIndex map (p => valueFor(p._1,p._2))
        (im reflectMethod method)(args: _*).asInstanceOf[A]
      }
    
      assert(Person(name = null) == newCase[Person]())
    }
    
  2. ==============================

    2.당신은 내부 API로 변환하여 이름-생성에 대한 가정을하지 않고이 작업을 수행 할 수 있습니다

    당신은 내부 API로 변환하여 이름-생성에 대한 가정을하지 않고이 작업을 수행 할 수 있습니다

    scala> :power
    ** Power User mode enabled - BEEP WHIR GYVE **
    ** :phase has been set to 'typer'.          **
    ** scala.tools.nsc._ has been imported      **
    ** global._, definitions._ also imported    **
    ** Try  :help, :vals, power.<tab>           **
    
    scala> case class Foo(id: Int, name: String, note: Option[String] = None)
    defined class Foo
    
    scala> val t = typeOf[Foo.type]
    t: $r.intp.global.Type = Foo.type
    
    scala> t.declaration(nme.defaultGetterName(nme.CONSTRUCTOR, 3))
    res0: $r.intp.global.Symbol = method <init>$default$3
    
    scala> t.declaration(nme.defaultGetterName(newTermName("apply"), 3))
    res1: $r.intp.global.Symbol = method apply$default$3
    

    방식 물론 이름 맹 글링을 지정하고 내부 API가되지 않기 때문에이 어떤 더 좋은 아니지만, 그것은 더 편리 할 수 ​​있습니다.

  3. from https://stackoverflow.com/questions/14034142/how-do-i-access-default-parameter-values-via-scala-reflection by cc-by-sa and MIT license