Jea*_*let 4 macros scala literals implicit-conversion
在我的应用程序中,我正在跟踪用户拥有的信用数量.要添加一些类型检查,我使用的Credits类与此类似:
case class Credits(val numCredits: Int) extends Ordered[Credits] {
...
}
Run Code Online (Sandbox Code Playgroud)
假设我有一个def accept(creds: Credits): Unit我想要调用的函数.有没有办法让我称之为
process(Credits(100))
process(0)
Run Code Online (Sandbox Code Playgroud)
但不是这个?
process(10)
Run Code Online (Sandbox Code Playgroud)
也就是说,我想仅从文字中提供隐式转换,0而不是其他.现在,我只是val Zero = Credits(0)在伴侣对象中,我认为这是一个相当不错的练习,但无论如何我都会对答案感兴趣,包括其他评论,例如:
Credits扩展AnyVal而不是2.10中的案例类?Edm*_*984 10
这种编译时检查是使用宏的良好地形,将在2.10中提供
一个非常聪明的人Jason Zaugg已经实现了类似于你需要的东西,但它适用于正则表达式:正则表达式编译时检查.
您可能希望查看其Macrocosm以了解它是如何完成的以及如何以相同的目的编写自己的宏.
https://github.com/retronym/macrocosm
如果你真的想了解更多有关宏的知识,首先我会说你需要勇敢,因为文档现在很少,而API很可能会改变.Jason Zaugg的作品与2.10-M3的编辑很好,但我不确定它是否适用于较新的版本.
如果你想从一些读数开始:
一个很好的切入点是scalamacros网站http://scalamacros.org/和SIP文档https://docs.google.com/document/d/1O879Iz-567FzVb8kw6N5OBpei9dnbW0ZaT7-XNSa6Cs/edit?pli=1
如果你有时间,你可能还想阅读Eugene Burmako的演讲:http://scalamacros.org/talks/2012-04-28-MetaprogrammingInScala210.pdf
现在,谈到主题,Scala宏是CAT:"编译时AST转换".抽象语法树是编译器表示源代码的方式.编译器将后续转换应用于AST,并在最后一步实际生成java字节码.
现在让我们来看看Jason Zaugg的代码:
def regex(s: String): scala.util.matching.Regex = macro regexImpl
def regexImpl(c: Context)(s: c.Expr[String]): c.Expr[scala.util.matching.Regex] = {
import c.universe._
s.tree match {
case Literal(Constant(string: String)) =>
string.r // just to check
c.reify(s.splice.r)
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所见,regex是一个特殊的函数,它通过调用宏regexImpl获取String并返回Regex
宏函数在第一个参数列表中接收上下文,在第二个参数列表中以c.Expr [A]的形式列出宏的参数并返回c.Expr [B].请注意,c.Expr是路径依赖类型,即它是在Context中定义的类,因此如果您有两个上下文,则以下内容是非法的
val c1: context1.Expr[String] = ...
val c2: context2.Expr[String] = ...
val c3: context1.Expr[String] = context2.Expr[String] // illegal , compile error
Run Code Online (Sandbox Code Playgroud)
现在,如果你看看代码中发生了什么:
这里发生的是在Predef.scala中定义了从字符串到StringOps的隐式转换,它在每个scala源的编译中自动导入
implicit def augmentString(x: String): StringOps = new StringOps(x)
StringOps扩展了scala.collection.immutable.StringLike,其中包含:
def r: Regex = new Regex(toString)
Run Code Online (Sandbox Code Playgroud)
由于宏是在编译时执行的,这将在编译时执行,如果抛出异常(即从无效的正则表达式字符串创建正则表达式的行为),编译将失败
注意:不幸的是,API非常不稳定,如果你查看 http://scalamacros.org/documentation/reference.html,你会看到一个关于Context.scala的断开链接.正确的链接是 https://github.com/scala/scala/blob/2.10.x/src/reflect/scala/reflect/makro/Context.scala
| 归档时间: |
|
| 查看次数: |
662 次 |
| 最近记录: |