我想这样做的唯一方法是使用宏。我曾经创建了一个执行以下操作的宏(请注意,当前实现中的一些细节发生了变化,因此是空的)。
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。更多关于宏现在的信息。
如果这是您要查找的内容,请告诉我,以便我查看是否可以将原始版本转换为工作版本。
编辑
我设法让旧的工作。要使用它,只需将代码复制粘贴到一个单独的项目中(我使用 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
函数内您可以执行相同的操作(更均匀一些)。