1

これを適切に定式化する方法(したがって、それを調べる方法)はわかりませんが、次のようになります。

オブジェクトに適用されたメソッドがどのように関数オブジェクトになるかを理解しています。例えば:

case class User(name: String, age: Int)
val user = User("", 0)
user.name _   // () => String

したがって、メソッドがあれば 、次のdef meth(f: () => String)ことができます。meth(user.name _)

class のメソッドをインスタンスとして持つを定義することはできますか? (より正確には、これらのメソッドから取得された関数オブジェクト) User

つまり、これを行うには、 の型は次fdef meth(f: ???)ようになります meth(user.name _)meth(user.age _)

ありがとう!

4

2 に答える 2

1

そのようなことを行う唯一の方法は、マクロを使用することだと思います。私はかつて、次のことを行うマクロを作成しました (現在の実装では一部の詳細が変更されたため、空になっていることに注意してください)。

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ますが、関数内で同じことを行うことができます (もう少し均一です)。

于 2013-02-19T21:54:07.943 に答える
0

あなたが探しているのは、Scala の「構造型」 (実際には Scala の革新ではありません) だと思います。

これは非名義型をキャプチャしますが、JVM でのその実装では、構造型によって指定されたメンバーに実際にアクセスまたは呼び出したいコード内のポイントでリフレクションを使用する必要があります。したがって、Scala で構造型を使用すると、かなりのオーバーヘッドが発生します。(必要なリフレクションから派生した情報のためにある種のキャッシュを実装するという話を聞いたことを思い出しますが、それが実装されたかどうかはわかりません)。

于 2013-02-19T16:40:48.990 に答える