代码之家  ›  专栏  ›  技术社区  ›  sksamuel

默认参数值方法位置

  •  4
  • sksamuel  · 技术社区  · 6 年前

    我在写一个宏,我试图找到生成本地case类默认值的方法的位置。

    例如,在顶级案例类中,例如:

    package foo
    
    case class Goo(a: String = "wibble")
    

    我可以很容易地找到返回“wibble”作为 <init>$default$N 在的伴生对象上定义 Goo .比如:

    val defswithsymbols = universe.asInstanceOf[Definitions with SymbolTable with StdNames]
    val defaultGetter = defswithsymbols.nme.defaultGetterName(defswithsymbols.nme.CONSTRUCTOR, index + 1)
    val method = tpe.companion.member(TermName(defaultGetter.toString))
    

    然后我可以调用 tpe.companion 给我默认值。

    但是,如果我在一个方法中定义了一个case类,那么这个类就没有伴生对象(我可以找到),因此我无法找到默认的参数生成方法。但它必须被定义在正确的地方:)

    编辑:我认为这个问题可能可以归结为——方法中声明的case类的伴生对象位于哪里?

    1 回复  |  直到 6 年前
        1
  •  0
  •   Constantine    6 年前

    编译case类时,编译器会为主类及其伴生对象创建类文件。对于在方法中定义的case类,它也是这样做的。唯一的区别是,类文件的创建文件名使其无法访问。它有点类似于匿名类文件名。

    例如:

    class TestClass {
      new Runnable(){
         def run() = {
            //some Code
         }
      }
    }
    

    编译上述代码后,编译器可能会生成名为 TestClass$anon$1 .如果您知道这个名称,可以使用反射创建这个匿名内部类的实例。

    请参考下面的示例代码,其中包含在方法中定义的case类。

    class TestClass {
      def someMethod = {
        case class ClassInsideMethod()
      }
    }
    
    object Main extends App{
      val enclosingClass = classOf[TestClass]
      val enclosingInstance = Class.forName(enclosingClass.getName).newInstance().asInstanceOf[TestClass]
      private val classInsideMethodConstructor = Class.forName(enclosingClass.getName + "$ClassInsideMethod$2").getDeclaredConstructor(enclosingClass)
      classInsideMethodConstructor.newInstance(enclosingInstance)
    }
    

    我发现在编译代码之后,编译器确实为case类创建了名为 TestClass$ClassInsideMethod$2 TestClass$ClassInsideMethod$3$ 类文件附加了一个数字。根据编译器的不同,此命名也会有所不同。在我的例子中,使用反射,我能够创建在方法中定义的case类的实例。

    太长,读不下去了编译器确实为case类创建了伴生对象。

    我希望这能回答你的问题。