【问题标题】:Code generation with Scala使用 Scala 生成代码
【发布时间】:2012-07-09 18:13:09
【问题描述】:

在 Scala 中使用 SBT 工具链时,是否可以编写一个任务来读取项目源代码的特殊部分以在编译时生成 scala 代码。

对此有任何想法甚至文章/教程吗?我正在寻找类似于 Template Haskell 的东西。

【问题讨论】:

  • 是的,有可能。我很确定有插件可以做到这一点。您是否查看过现有插件列表?

标签: scala code-generation template-haskell


【解决方案1】:

treehugger.scala 是一个专为代码生成而设计的库。

import treehugger.forest._
import definitions._
import treehuggerDSL._

val tree: Tree = Predef_println APPLY LIT("Hello, world!")

println(tree)
println(treeToString(tree))

上面的代码打印了两行:

Apply(Ident(println),List(Literal(Constant(Hello, world!))))
println("Hello, world!")

treehugger 确实会生成一个 AST,但不符合 scalac 的 AST。

【讨论】:

  • 澄清一下:treehugger = 源代码生成;宏 = AST 生成。前者技术含量较低,这实际上可能是一个优势:)
  • @EugeneYokota,是否计划在附近发布 Scala 2.10?
【解决方案2】:

Scala 2.10 对宏具有实验性支持,类似于复杂的编译时代码生成。详情请参阅here

在 Jason Zaugg 的 macrocosm git 存储库和 SLICK 库中有一些有趣的示例,它是 ScalaQuery SQL DSL 的演变,能够以类似 LINQ 的方式表达类型安全的数据库(和集合)查询方式。

这个例子,来自expecty 断言库:

import org.expecty.Expecty

case class Person(name: String = "Fred", age: Int = 42) {
  def say(words: String*) = words.mkString(" ")
}

val person = Person()
val expect = new Expecty()

...
val word1 = "ping"
val word2 = "pong"

expect {
  person.say(word1, word2) == "pong pong"
}

产量:

java.lang.AssertionError:

person.say(word1, word2) == "pong pong"
|      |   |      |      |
|      |   ping   pong   false
|      ping pong
Person(Fred,42)

【讨论】:

  • 预计它们何时会成为完整功能?
  • 我相信编译器开发团队正在 2.10 中试用它们,看看社区发现它们有多大用处。当前的想法(截至几周前我上次阅读内部邮件列表时)是他们仍然保留仅将它们作为实验性的可能性。但如果社区支持非常积极,我想他们会被采纳。不过,这个网站上还有其他人可能会给你一个更明确的答案。
  • 它们看起来很像 Template Haskell,并且被广泛使用。尽管在很多情况下 Scala 可以在没有这个的情况下很好地服务(比如复杂类的自动扩展)。但就我的目的而言,在编译时预处理资产是合适的。
【解决方案3】:

我最近做了一些研究。几乎有 3 个选项可用:

  1. 字符串模板。
  2. 抱树者
  3. Scala 宏

更多详情:http://yefremov.net/blog/scala-code-generation/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-13
    • 2023-03-19
    • 2012-12-21
    • 2011-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多