scala - 在 Scala 2.10 中使用带有宏的附件

标签 scala scala-macros

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

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

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

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

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. */ ???
}

这似乎是attachments 的那种事情。旨在帮助(感谢 Eugene Burmako for the pointer ),我有一个基于附件的实现,允许我编写以下内容:
Foo("whatever.txt").lookup("x")

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

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

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

最佳答案

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

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

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

  }

}

关于scala - 在 Scala 2.10 中使用带有宏的附件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17580781/

相关文章:

scala - 我如何更改 sbt 使用的 Scala 版本?

scala - 为什么以及如何在调用单参数函数时特别处理元组?

scala - 如何初始化元组列表并在scala中添加项目

scala - 是否有一个类型类来检查是否存在至少一个隐式类型?

scala - 如何使用 scala 宏创建函数对象(创建 Map[String, (T) => T])

scala - 为什么会出现Conflicting cross-version suffixes的错误?

java - 用 Java 重用正在运行的进程 ||斯卡拉

scala - 使用宏转换树后重新建立类型一致性的最佳方法是什么

scala - 从 SBT 项目中的宏读取资源

scala - Scala 错误 SI-7914 - 从 Scala 宏返回应用方法是否有任何解决方法?