我想这样做的唯一方法是使用宏。我曾经创建了一个执行以下操作的宏(请注意,当前实现中的一些细节发生了变化,因此是空的)。
case class Metadata(instance: AnyRef, name: String) {
def value = ??? // use reflection to invoke `name` on `instance`
}
object Metadata extends ((AnyRef, String) => Metadata) {
implicit def anyToMetadata(sym: Any): Metadata =
macro MetadataMacro.anyToMetadataImpl
}
private[staticReflection] object MetadataMacro {
def anyToMetadataImpl(c: Context)(sym: c.Expr[Any]): c.Expr[Metadata] = {
import c.universe._
val metadata = // match the tree and create the appropriate metadata instance
c.Expr(metadata)
}
}
在代码中你会像这样使用它:
case class User(name:String)
def test(metadata:Metadata) {
println(metadata.name + "->" + metadata.value)
}
val u = User("test")
test(u.name) // name -> test
几乎一年前有效的代码可以在这里找到:ee/scala/staticReflection/Metadata.scala。有关macros as they are now 的更多信息。
如果这是您要查找的内容,请告诉我,以便我查看是否可以将原始版本转换为工作版本。
编辑
我设法让旧的工作。要使用它,只需将代码复制粘贴到一个单独的项目中(我使用 Eclipse),然后通过 Java Build Path 链接这些项目。工作版本:
package ee.scala.staticReflection
import scala.language.experimental.macros
import scala.reflect.macros.Context
import language.implicitConversions
case class Metadata(instance: AnyRef, name: String) {
// any comments on how to improve this part are welcome
val runtimeUniverse = scala.reflect.runtime.universe
val mirror = runtimeUniverse.runtimeMirror(getClass.getClassLoader)
val instanceMirror = mirror.reflect(instance)
val method = instanceMirror.symbol.selfType.member(runtimeUniverse newTermName name).asMethod
val methodMirror = instanceMirror.reflectMethod(method)
def value = methodMirror()
}
object Metadata extends ((AnyRef, String) => Metadata) {
implicit def anyToMetadata(sym: Any): Metadata = macro MetadataMacro.anyToMetadataImpl
}
private[staticReflection] object MetadataMacro {
def anyToMetadataImpl(c: Context)(sym: c.Expr[Any]): c.Expr[Metadata] = {
import c.universe._
def createMetadataInstance(select: Select): Tree =
treeBuild.mkMethodCall(
c.mirror.staticModule("ee.scala.staticReflection.Metadata"),
newTermName("apply"),
List(select.qualifier, Literal(Constant(select.name.toString))))
val metadata = sym.tree match {
//normal select
case select: Select => createMetadataInstance(select)
//could be a call using a right associative operator
case Ident(name) =>
c.enclosingMethod.collect {
case ValDef(_, refName, _, select: Select) if refName == name => createMetadataInstance(select)
}
.headOption
.getOrElse(throw new Exception("Could not find ValDef for " + name))
case _ => throw new Exception("Could not create metadata")
}
c.Expr(metadata)
}
}
编辑 2
将以上所有内容应用于原始海报的问题。你可以这样使用它
case class User(name: String, age: Int)
val user = User("", 0)
def meth(metadata: Metadata) = {
println(metadata.name + "->" + metadata.value)
}
meth(user.name)
meth(user.age)
请注意,解决方案与建议的不同,但在 meth 函数中,您可以执行相同的操作(更均匀一些)。