6

更新:我怀疑我想要的可能是不可能的,我已经写了一篇博客文章,其中包含我的推理(和一些替代方案)here。我会很高兴被告知我错了。


假设我想使用带有宏实现的工厂方法创建特征的实例。这个方法将把一个资源的路径作为参数,宏将读取和解析(在编译时)从字符串到字符串的映射。

那部分都很简单。现在假设我想将生成的映射与我正在创建的实例相关联,以便我可以在涉及该实例的后续宏调用中使用它。

非常不希望地图成为实例的成员,或者在运行时以任何形式存在。我也不想多次解析同一个资源。这是我要实现的目标的草图:

import scala.language.experimental.macros
import scala.reflect.macros.Context

trait Foo {
  def lookup(key: String): String = macro Foo.lookup_impl
}

object Foo {
  def parseResource(path: String): Map[String, String] = ???

  def apply(path: String): Foo = macro apply_impl

  def apply_impl(c: Context)(path: c.Expr[String]): c.Expr[Foo] = {
    import c.universe._

    val m = path.tree match {
      case Literal(Constant(s: String)) => parseResource(s)
    }

    val tree = reify(new Foo {}).tree
    // Somehow associate the map with this tree here.
    c.Expr(tree)
  }

  def lookup_impl(c: Context)(key: c.Expr[String]): c.Expr[String] =
    /* Somehow read off the map and look up this key. */ ???
}

这似乎是附件旨在帮助解决的事情(感谢Eugene Burmako指针),我有一个基于附件的实现,允许我编写以下内容:

Foo("whatever.txt").lookup("x")

Whereapply_impl将地图附加到树上并lookup_impl从同一棵树中读取该附件,并将其视为其前缀。不幸的是,这或多或少没用,因为它foo.lookup("x")在前缀树只是变量的情况下不起作用foo

(请注意,在我的实际用例中Fooextends Dynamic,并且我试图为selectDynamic而不是提供宏实现lookup,但这在这里不应该相关 - 我对一般情况感兴趣。)

有什么方法可以让我使用附件来获得我想要的东西吗?还有其他更合适的方法吗?

4

1 回答 1

0

更新我应该在摆弄之后再次阅读这个问题...... :(我刚刚复制了你所拥有的。


我想你在那里。这对我有用:

object Foo {

  // Attachment.get somehow needs a wrapper class.
  // Probably because of generics
  implicit class LookupMap(m: Map[String, String]) {
    def get(s: String) = m.get(s) 
  }

  def parseResource(path: String): LookupMap = Map("test" -> "a")

  def apply_impl(c: Context)(path: c.Expr[String]): c.Expr[Foo] = {
    import c.universe._

    val m = path.tree match {
      case Literal(Constant(s: String)) => parseResource(s)
    }

    val tree = reify(new Foo {}).tree.updateAttachment(m)

    c.Expr(tree)
  }

  def lookup_impl(c: Context { type PrefixType = Foo })
                 (key: c.Expr[String]): c.Expr[String] = {
    import c.universe._

    val m = c.prefix.tree.attachments.get[LookupMap].get

    val s = key.tree match {
      case Literal(Constant(s: String)) => m.get(s).get
    }

    c.Expr(Literal(Constant(s)))

  }

}
于 2013-07-11T00:51:25.913 回答