不知道如何正确地表达这个(因此,如何查看它),但这里有:
我理解应用于对象的方法如何变成一个函数对象。例如:
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 的。详细了解现在的宏。
如果这是您要查找的内容,请让我知道,以便我可以查看是否可以将原件转换为正常版本。
编辑我设法让旧的工作。要使用它,只需将代码复制到单独的项目中(我使用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 _ // () => StringSo, 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 -> testThe 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.
EditI 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).
更多推荐
单个类的所有方法的函数类型
发布评论