そのようなことを行う唯一の方法は、マクロを使用することだと思います。私はかつて、次のことを行うマクロを作成しました (現在の実装では一部の詳細が変更されたため、空になっていることに注意してください)。
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
ほぼ 1 年前に有効だったコードは、次の場所にあります: 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
ますが、関数内で同じことを行うことができます (もう少し均一です)。