单一类的所有方法函数类型 - 斯卡拉(Function type of all methods of

2019-10-17 17:59发布

不知道如何正确地制定本(因此,如何看待它),但这里有云:

我知道如何应用到对象的方法可以成为一个函数对象。 例如:

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

所以,如果我有一个方法def meth(f: () => String) ,我可以这样做: meth(user.name _)

是可以定义具有作为实例类的方法 类型 User ? (由这些方法获得的功能的目的,更确切地说)

为了话,会有什么类型fdef meth(f: ???)是,为了能够做到这一点: meth(user.name _)meth(user.age _)

谢谢!

Answer 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

因为它是有效的差不多一年前的代码可以在这里找到: EE /斯卡拉/ 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功能,您可以(甚至更多一点)这样做。



Answer 2:

我相信你在寻找什么是Scala的“结构型”(不是一个真正的斯卡拉创新)。

它捕获的非正常打字,但其对JVM实现就必须要实际访问或调用由结构类型决定成员在你的代码点使用反射。 因此,有一个与Scala的使用结构类型相关联一个漂亮的非平凡的开销。 (我记得听到谈论实现某种缓存所需的反射得出的信息,但我不知道这是有史以来实现的)。



文章来源: Function type of all methods of a single class - in Scala