使用宏将 import 语句粘贴到 thunk 前面

2024-01-09

触发于这个问题 https://stackoverflow.com/questions/18535356/multiple-late-initialisation,我想知道是否可以编写一个 def-macro 来实现结果:

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

object CarImpl {
  def impl(c: Context)(fun: c.Expr[Unit]): c.Expr[Unit] = {
    import c.universe._
    val all  = "_": TermName
    val imp  = c.Expr(Import(c.prefix.tree, ImportSelector(all, -1, all, -1) :: Nil))
    val tree = reify {
      imp.splice
      fun.splice
    } .tree
    c.Expr(tree)
  }
}
class Car(var speed: Int, var color: String) {
  def set(fun: Unit): Unit = macro CarImpl.impl
}

应用:

val myCar = new Car(5, "red")
myCar.set { color = "blue" }

这无法编译,因为:not found: value color。似乎将 import 语句“粘贴”在它前面还不够。如果总体想法可以实现,有什么线索吗?也就是说,以下应该是合成输出

val myCar = new Car(5, "red")

{
  import myCar._
  color = "blue"
}

可以获得这种语法,但是需要一种涉及结构类型的疯狂技巧(并且需要额外的一行样板文件)。我写过一篇博文 http://meta.plasm.us/posts/2013/08/30/horrible-code/详细讨论该技巧,并将在此处给出简化版本。

首先是宏实现set(请注意,我使用的是 quasiquotes,现在可以在 2.10 中作为插件使用):

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

trait SetterBuilder {
  def set_impl(c: Context)(assignments: c.Expr[Unit]): c.Expr[Unit] = {
    import c.universe._

     val rewriteOne: PartialFunction[Tree, Tree] = {
       case q"${_}.$n($v)" => q"${c.prefix}.$n($v)"
     }

     val rewrite: PartialFunction[Tree, Tree] = rewriteOne orElse {
       case block: Block => q"{ ..${block collect rewriteOne} }"
     }

     c.Expr(
       rewrite.lift(assignments.tree).getOrElse(
         c.abort(c.enclosingPosition, "Not a set of assignments!")
       )
     )
  }
}

然后是结构类型:

trait SyntaxBuilder {
  def syntax_impl[A: c.WeakTypeTag](c: Context) = {
    import c.universe._

    val anon = newTypeName(c.fresh())
    val declarations = c.weakTypeOf[A].declarations

    val (getters, setters) = declarations.collect {
      case sym: MethodSymbol if sym.isSetter => (
        q"def ${sym.getter.name} = ???",
        q"def ${sym.name}(x: ${sym.paramss.head.head.typeSignature}) = ???"
      )
    }.unzip

    c.Expr[Any](q"class $anon { ..$getters; ..$setters }; new $anon {}")
  }
}

现在我们将它们结合在一起并定义我们的类:

object Evil extends SyntaxBuilder with SetterBuilder {
  def syntax[A] = macro syntax_impl[A]
}

case class Car(var speed: Int, var color: String) {
  def set(assignments: Unit): Unit = macro Evil.set_impl
}

object Car {
  val syntax = Evil.syntax[Car]
}

我们把样板文件放在一边:

import Car.syntax._

我们就完成了:

scala> val car = new Car(0, "blue")
car: Car = Car(0,blue)

scala> car set {
     |   color = "red"
     |   speed = 10000
     | }

scala> car
res0: Car = Car(10000,red)

See 博客文章 http://meta.plasm.us/posts/2013/08/30/horrible-code/获取功能更齐全的版本、解释以及为将这段糟糕的代码引入世界而道歉。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用宏将 import 语句粘贴到 thunk 前面 的相关文章

随机推荐

  • 具有多个手柄的 JQuery UI 滑块:如何阻止手柄交叉?

    我正在开发一个快速解决方案 它使用具有多个手柄的滑块来定义动态布局的宽度 我尝试使用 ExtJS3 和最新的 JQuery UI 在 ExtJS 中 您可以限制句柄 这样它们就不会相互交叉 这是一种实现我需要的 UI 的非常直观的方法 但是
  • 初始化集合时,哈希集对内存有何作用?

    我偶然发现了以下问题 我想要一个包含从 1 到 100 000 000 的所有数字的哈希集 我尝试了以下代码 var mySet new HashSet
  • ServiceStack OrmLite 命令超时

    使用 IDbConnection ExecuteSql 时如何设置命令超时 IDbConnection db ConnectionFactory OpenDbConnection db ExecuteSql 如果我使用 IDbCommand
  • 在撰写中禁用横向模式

    如何禁用可组合函数的横向模式 我想始终以纵向模式显示可组合项 PS 无法在活动的清单文件中设置它 因为我只希望此行为适用于一个可组合项 而不适用于活动中的其他可组合项 你可以这样做DisposableEffect 活动requestedOr
  • 线程:PyQt 因“出队时队列中存在未知请求”而崩溃

    我正在开发的应用程序的一部分需要向一小群人发送一些电子邮件 由于连接到 SMTP 服务器并发送电子邮件可能需要一些时间 因此我想在此操作期间使用后台线程来提供一个进度条来完成这项工作 现在发生的情况是 我可以实现一个工作得很好的测试结构 但
  • PHP 中如何判断 value 是否为日期

    我正在使用 PHP 中的值数组 其中一些值可能包括各种字符串格式的日期 我需要将多种格式的日期转换为它们的等效数字 Unix 时间戳 问题是能够确定字符串是否是日期 Using if timestamp strtotime str fals
  • Android:加密密码[重复]

    这个问题在这里已经有答案了 可能的重复 存储密码 https stackoverflow com questions 5359399 storing a password 我正在使用共享首选项来存储密码 按原样保存密码数据是否安全 或者我必
  • Three.js 中的渐进式加载/LOD/流网格

    我正在使用 STL 加载器将 stl 文件加载到 Three js 场景中 这些 stl 文件的大小从 5mb 到 50mb 不等 有没有一种方法可以用来在模型加载时逐步加载 流式传输 提高细节级别 不确定术语是否正确 以便我的用户在出现任
  • R 按组总和总结给出 NA

    我有一个像这样的数据框 Observations 2 190 835 Variables 13 patientid
  • Angular 2 自定义复合控件

    我正在尝试为 Angular 2 创建一个自定义复合控件 我的要求是我需要创建一个允许用户选择文件的通用文件选择器控件either使用 html5 输入 类型 文件 or通过输入文件的 url 我决定创建通用表单控件 为两个子控件实现 Co
  • 何时对卷积层使用什么类型的填充?

    我知道当我们在神经网络中使用卷积层时 我们通常使用填充并且主要使用恒定填充 例如零填充 并且有不同类型的填充 例如对称 反射 恒定 但我不确定使用不同填充方法的优点和缺点以及何时使用哪一种 这实际上取决于神经网络的用途的情况 我不会告诉它的
  • Bootstrap 表 - 无法在 tr 上添加点击事件

    我正在使用 Bootstrap 表 http wenzhixin net cn p bootstrap table docs index html http wenzhixin net cn p bootstrap table docs i
  • AOP 围绕外部库的重写方法?

    我正在寻找以下问题的实用解决方案 外部库提供组件作为基类 自定义组件是通过扩展这些基类来创建的 当实现抛出未处理的异常时 基类就会中断 基类源代码不可用 只有一个二进制罐子 我正在寻找的是一个通用的 AOP 错误处理建议 它将包装每个方法的
  • 如何使用 React 前端将 favicon 添加到 django 应用程序

    我正在构建一个带有 React 前端的 Django 应用程序 使用 React create app 构建 我无法让图标出现在生产中 我正在使用 Django 2 10 0 当我构建 React 应用程序时 构建输出文件将放在 asset
  • Visual Studio 2013 与 2010 项目兼容吗?

    VS2012 可以打开 VS2010 项目并使它们处于可在 VS2010 中使用的状态 VS2013有同样的功能吗 如果允许 Visual Studio 自动升级项目 则可以在 Visual Studio 2013 Visual Studi
  • 从 Android 应用程序登录网页

    我正在努力做到这一点 我真的需要有经验的朋友的帮助 带有 2 个文本框的应用程序 一份用于用户名 一份用于密码 登录按钮 当用户按下按钮时 登录信息将发送到网页 m bonbon hr 并在浏览器中打开该网页 首次登录后 登录信息将被保存
  • 找不到接口 java.util.List Rest API Spring boot 的主要或默认构造函数

    我将请求正文传递给邮递员上的 POST 请求 类似于以下内容 name Mars artifacts elements name carbon amount 0 5 measurement g typeName typeA elements
  • 使用 ShouldBeEquivalentTo 并处理不同的名称

    我想做一个映射器测试 将数据库模型映射到 dto 数据库模型中有 class Order long Id 但在 Dto 上 同一个字段被命名为 class OrderDto long OrderId 使用 ShouldBeEquivalen
  • PayPal 和 Parse 冲突

    尝试使用 PayPal iOS SDK 使其能够仅与 Paypal 集成一起工作 但是当我尝试添加任何解析所需的框架 例如 Parse framework Boltz framework 和 ParseFacebookUtils frame
  • 使用宏将 import 语句粘贴到 thunk 前面

    触发于这个问题 https stackoverflow com questions 18535356 multiple late initialisation 我想知道是否可以编写一个 def macro 来实现结果 import scal