单个类的所有方法的函数类型 - 在Scala中 [英] Function type of all methods of a single class - in Scala

查看:127
本文介绍了单个类的所有方法的函数类型 - 在Scala中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

不知道如何正确地表达这个(因此,如何查看它),但这里有:



我理解应用于对象的方法如何变成一个函数对象。例如:

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

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



是否可以定义一个类型,它具有类的方法作为实例 User ?
(从这些方法获得的函数对象,更确切地说)

换句话说, f def meth(f:???)是,为了能够做到这一点: meth(user.name _ ) meth(user.age _)



谢谢!

解决方案

我想要做这样的事情的唯一方法就是使用宏的。我曾经创建了一个执行以下操作的宏(请注意,当前实现中的一些细节已更改,因此为空)。

  case class Metadata(实例:AnyRef,name:String){

def value = ??? //(使用反射来调用`instance`上的`name`
}

对象元数据扩展((AnyRef,String)=>元数据){

隐式def anyToMetadata(sym:Any):Metadata =
macro MetadataMacro.anyToMetadataImpl
}
$ b $ private [staticReflection] object MetadataMacro {

def anyToMetadataImpl(c :Context)(sym:c.Expr [Any]):c.Expr [Metadata] = {

import c.universe._

val metadata = // match树并创建适当的元数据实例

c.Expr(元数据)
}
}

在代码中,您可以像这样使用它:

  case class User :字符串)

def test(元数据:元数据){
println(metadata.name + - >+ metadata.value)
}

val u = User(test)

test(u.name)// name - >测试

大约一年前有效的代码可以在这里找到: ee / scala / staticReflection / Metadata.scala 的。详细了解现在的宏



如果这是您要查找的内容,请让我知道,以便我可以查看是否可以将原件转换为正常版本。



< hr>

编辑



我设法让旧的工作。要使用它,只需将代码复制到单独的项目中(我使用Eclipse),然后通过 Java Build Path 链接项目。工作版本:

 包ee.scala.staticReflection 

导入scala.language.experimental.macros
import scala.reflect.macros.Context
import language.implicitConversions

case class元数据(实例:AnyRef,name:String){
//关于为了改进这部分,欢迎
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()
元数据扩展((AnyRef,String)=>元数据){

implicit def anyToMetadata(sym:Any):Metadata = macro MetadataMacro.anyToMetadataImpl
}

private [staticReflection] object MetadataMacro {

def anyTo MetadataImpl(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(常量(select.name.toString))))

val元数据= sym.tree匹配{
//正常选择
case select:Select => ; createMetadataInstance(select)

//可以是使用右关联运算符的调用
case Ident(name)=>
c.enclosingMethod.collect {
case ValDef(_,refName,_,select:Select)if refName == name => createMetadataInstance(select)
}
.headOption
.getOrElse(抛出新的异常(无法找到ValDef for+ name))

case _ => (无法创建元数据)
}

c.Expr(元数据)
}
}






编辑2



全部应用上面的东西的原始海报的问题。您可以像这样使用它。

  case class User(name:String,age:Int)
val user = User (元数据:元数据)= {
println(metadata.name + - >+ metadata.value)
} $ b(,0)

def meth
$ b meth(user.name)
meth(user.age)

请注意,解决方案与建议的不同,但在 meth 函数中,您可以执行相同的操作(更均匀一些)。


Not sure how to properly formulate this (hence, how to look it up), but here goes:

I understand how a method applied to an object can become a function object. For example:

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

So, if I had a method def meth(f: () => String), I could do: meth(user.name _)

Is is possible to define a type that has as instances the methods of class User ? (the function objects obtained from these methods, more precisely)

In order words, what would the type of f in def meth(f: ???) be, in order to be able to do this: meth(user.name _) and meth(user.age _)

Thanks!

解决方案

I guess the only way to do something like that is to use macro's. I once created a macro that does the following (note that some details changed in the current implementation and thus are empty).

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)
  }
}

In code you would then use it like this:

case class User(name:String)

def test(metadata:Metadata) {
  println(metadata.name + "->" + metadata.value)
}

val u = User("test")

test(u.name) // name -> test

The code as it was valid almost a year ago can be found here: ee/scala/staticReflection/Metadata.scala. More info about macros as they are now.

If this is what you were looking for, please let me know so I can see if I can convert the original to a working version.


Edit

I managed to get the old one working. To use it simply copy-past the code into a separate project (I use Eclipse) and then link the projects via the Java Build Path. Working version:

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)
  }
}


Edit 2

To apply all of the above stuff to the question of the original poster. You could use it like this

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)

Note that the solution is different from what was proposed, but within the meth function you can do the same (a bit more even).

这篇关于单个类的所有方法的函数类型 - 在Scala中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆