如果一个构造器参数是隐式的,我如何在Scala中使用反射来检测?

klr1opcd  于 7个月前  发布在  Scala
关注(0)|答案(1)|浏览(76)

假设我有一个

class A(msg: String)(using ctx1: Int, ctx2: Long)

我想告诉你,它有两个隐式参数使用反射。
我试过类似的方法

val m = runtimeMirror(getClass.getClassLoader)
println(m.classSymbol(getClass).primaryConstructor.info.paramLists)

但这仅识别一个参数列表。
还尝试了isImplicit

println(m.classSymbol(getClass).primaryConstructor.info.paramLists.head.map(_.asTerm.isImplicit))

它没有工作,返回所有false。
我使用Scala 3.3

mzaanser

mzaanser1#

这是用2.13和3编译的代码之间的区别。
当你在2.13中编译这段代码时:

import scala.reflect.runtime.universe._

class B(msg: String)(implicit ctx1: Int, ctx2: Long)

locally {
  val b = classOf[B]
  val m = runtimeMirror(b.getClassLoader)
  println(m.classSymbol(b).primaryConstructor)
  println(m.classSymbol(b).primaryConstructor.info)
  println(m.classSymbol(b).primaryConstructor.info.paramLists)
}

你会得到这样的结果:

constructor B
(msg: String)(implicit ctx1: Int, ctx2: Long): Playground.B
List(List(value msg), List(value ctx1, value ctx2))

请参见Scastie
在Scala 3中:

import scala.reflect.runtime.universe.*

class A(msg: String)(using ctx1: Int, ctx2: Long)

locally {
  val a = classOf[A]
  val m = runtimeMirror(a.getClassLoader)
  println(m.classSymbol(a).primaryConstructor)
  println(m.classSymbol(a).primaryConstructor.info)
  println(m.classSymbol(a).primaryConstructor.info.paramLists)
}

class B(msg: String)(implicit ctx1: Int, ctx2: Long)

locally {
  val b = classOf[B]
  val m = runtimeMirror(b.getClassLoader)
  println(m.classSymbol(b).primaryConstructor)
  println(m.classSymbol(b).primaryConstructor.info)
  println(m.classSymbol(b).primaryConstructor.info.paramLists)
}

打印:

constructor A
(msg: String, ctx1: Int, ctx2: Long): Playground.A
List(List(value msg, value ctx1, value ctx2))
constructor B
(msg: String, ctx1: Int, ctx2: Long): Playground.B
List(List(value msg, value ctx1, value ctx2))

参见Scastie
我相信原因是:

  • Scala 2.13和Scala 3的字节码略有不同(Scala 3也使用Tasty文件)
  • Scala 2.13和Scala 3编译器知道如何读取彼此的字节码(尽管Scala 2.13需要-Ytasty-reader标志)
  • Scala反射库是一个不仅为2.13编译的库,而且还编写了它,以便从字节码中读取Scala的元数据,并使用此知识提供普通Java反射不知道的信息
  • 但是2.13的库并没有被调整为以字节码的形式读取Scala 3的元数据

因此,当你编译Scala 3代码时,添加一个对Scala 2.13库的依赖,编译器可以读取和使用这个库,但是库不能读取Scala 3提供的额外的字节码属性/Tasty。
因此,您看到的是JVM所看到的,即未curry的方法。

相关问题