StringContext 和宏:一个简单的示例

2024-01-07

我正在努力实现一个StringContext扩展名允许我这样写:

val tz = zone"Europe/London" //tz is of type java.util.TimeZone

但附加的警告是如果提供的时区无效,它应该无法编译(假设可以在编译时确定)。

这是一个辅助函数:

def maybeTZ(s: String): Option[java.util.TimeZone] =
  java.util.TimeZone.getAvailableIDs collectFirst { case id if id == s =>
    java.util.TimeZone.getTimeZone(id)
  }

我可以非常轻松地创建一个非宏实现:

scala> implicit class TZContext(val sc: StringContext) extends AnyVal {
 |   def zone(args: Any *) = {
 |     val s = sc.raw(args.toSeq : _ *)
 |     maybeTZ(s) getOrElse sys.error(s"Invalid zone: $s")
 |   }
 | }

Then:

scala> zone"UTC"
res1: java.util.TimeZone = sun.util.calendar.ZoneInfo[id="UTC",offset=0,...

到目前为止,一切都很好。但如果时区无意义(例如,zone"foobar");代码在运行时失败。我想将其扩展到宏,但是,尽管阅读了docs http://docs.scala-lang.org/overviews/macros/overview.html,我真的很难处理细节(准确地说,是所有细节。)

有人可以帮助我从这里开始吗?全面唱歌、全面跳舞的解决方案应该看看是否StringContext定义任何参数并且(如果是这样),将计算推迟到运行时,否则尝试在编译时解析区域


我尝试了什么?

嗯,宏定义似乎必须位于静态可访问的对象中。所以:

package object oxbow {
  implicit class TZContext(val sc: StringContext) extends AnyVal {
    def zone(args: Any *) = macro zoneImpl //zoneImpl cannot be in TZContext
  }

  def zoneImpl(c: reflect.macros.Context)
    (args: c.Expr[Any] *): c.Expr[java.util.TimeZone] = {
      import c.universe._
      //1. How can I access sc from here?

      /// ... if I could, would this be right?
      if (args.isEmpty) {
        val s = sc.raw()
        reify(maybeTZ(s) getOrElse sys.error(s"Not valid $s")) 
      }
      else {
        //Ok, now I'm stuck. What goes here?
      }
    }

}

根据下面 som-snytt 的建议,这是最新的尝试:

def zoneImpl(c: reflect.macros.Context)
           (args: c.Expr[Any] *): c.Expr[java.util.TimeZone] = {
  import c.universe._
  val z =
    c.prefix.tree match {
      case Apply(_, List(Apply(_, List(Literal(Constant(const: String)))))) => gsa.shared.datetime.XTimeZone.getTimeZone(const)
      case x => ??? //not sure what to put here
    }

  c.Expr[java.util.TimeZone](Literal(Constant(z))) //this compiles but doesn't work at the use-site
                             ^^^^^^^^^^^^^^^^^^^
                             this is wrong. What should it be?
}

在使用现场,有效zone"UTC"编译失败并出现以下错误:

java.lang.Error: bad constant value: sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null] of class class sun.util.calendar.ZoneInfo

想必我不应该使用Literal(Constant( .. ))将其括起来。我应该用什么?


最后一个例子 - 基于下面特拉维斯·布朗的回答

def zoneImpl(c: reflect.macros.Context)
         (args: c.Expr[Any] *): c.Expr[java.util.TimeZone] = {
  import c.universe._
  import java.util.TimeZone

  val tzExpr: c.Expr[String] = c.prefix.tree match {
    case Apply(_, Apply(_, List(tz @ Literal(Constant(s: String)))) :: Nil)
      if TimeZone.getAvailableIDs contains s => c.Expr(tz)
    case Apply(_, Apply(_, List(tz @ Literal(Constant(s: String)))) :: Nil) =>
      c.abort(c.enclosingPosition, s"Invalid time zone! $s")
    case _ => ??? 
//            ^^^ What do I do here? I do not want to abort, I merely wish to 
//                "carry on as you were". I've tried ... 
//                    c.prefix.tree.asInstanceOf[c.Expr[String]]
//                ...but that does not work
  }
  c.universe.reify(TimeZone.getTimeZone(tzExpr.splice))

}

这是处理时区插值的“歌舞”解决方案:

package object timezone {
  import scala.language.implicitConversions
  implicit def zoned(sc: StringContext) = new ZoneContext(sc)
}

package timezone {
  import scala.language.experimental.macros
  import scala.reflect.macros.Context
  import java.util.TimeZone

  class ZoneContext(sc: StringContext) {

    def tz(args: Any*): TimeZone = macro TimeZoned.tzImpl

    // invoked if runtime interpolation is required
    def tz0(args: Any*): TimeZone = {
      val s = sc.s(args: _*)
      val z = TimeZoned maybeTZ s getOrElse (throw new RuntimeException(s"Bad timezone $s"))
      TimeZone getTimeZone z
    }
  }
  object TimeZoned {
    def maybeTZ(s: String): Option[String] =
      if (TimeZone.getAvailableIDs contains s) Some(s) else None

    def tzImpl(c: Context)(args: c.Expr[Any]*): c.Expr[TimeZone] = {
      import c.universe._
      c.prefix.tree match {
        case Apply(_, List(Apply(_, List(tz @Literal(Constant(const: String)))))) =>
          maybeTZ(const) map (
            k => reify(TimeZone getTimeZone c.Expr[String](tz).splice)
          ) getOrElse c.abort(c.enclosingPosition, s"Bad timezone $const")
        case x =>
          val rts = x.tpe.declaration(newTermName("tz0"))
          val rt = treeBuild.mkAttributedSelect(x, rts)
          c.Expr[TimeZone](Apply(rt, args.map(_.tree).toList))
      }
    }
  }
}

Usage:

package tztest 

import timezone._

object Test extends App {

  val delta = 8
  //Console println tz"etc/GMT+$delta"  //java.lang.RuntimeException: Bad timezone etc/GMT+8
  Console println tz"Etc/GMT+$delta"
  Console println tz"US/Hawaii"
  //Console println tz"US/Nowayi"     //error: Bad timezone US/Nowayi
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

StringContext 和宏:一个简单的示例 的相关文章

  • Akka/Scala:映射 Future 与 pipelineTo

    In Akka参与者 在发送一个Future结果给另一个演员 A 映射Future发挥作用tell结果给演员 B 定义一个onSuccess未来的回调 其中tell结果给演员 C 管道Future结果给演员pipeTo 其中一些选项已在上一
  • scala 中的模拟案例类:Mockito

    在我的游戏应用程序中 我打算模拟一个案例类 我可以这样做 但它创建了一个所有成员变量都为空的对象 有没有办法创建案例类的模拟对象 以便该对象可以初始化一些成员 case class User name String address Stri
  • 为什么我可以使用 Scala REPL 中的 Java 库,但不能使用脚本中的 Java 库?

    我正在开发一个使用 Joda Time 的 Scala 脚本 直到今天 这一切都运行良好 不知怎的 有些东西发生了变化 它不再起作用了 这有效 scala cp lib Welcome to Scala version 2 9 1 fina
  • Scala - lambda 参数可以匹配元组吗?

    所以说我有一些清单 比如 val l List 1 blue 5 red 2 green 然后我想过滤掉其中一个 我可以做类似的事情 val m l filter item gt val n s item unpack the tuple
  • 在 scala 中保留推导的更高类型

    我有一个高阶类型 并致力于用它构建一些 DSL 我正在寻找一种方法来定义可以接受类型而无需显式指定此类型的函数 自我描述示例 class Wrap T val data T class DSL def doSomething T x Wra
  • Scala Sparkcollect_list() 与 array()

    有什么区别collect list and array 在 Spark 中使用 scala 我看到到处都有使用情况 但我不清楚用例来确定差异 尽管两者array https spark apache org docs latest api
  • 用 HashMap[Int, Vector[Int]] (Scala) 表示图(邻接列表)?

    我想知道如何 如果可能的话 我可以通过以下方式制作 可变 图的邻接列表表示HashMap Int Vector Int HashMap当然是可变的 目前我将其设置为HashMap Int ArrayBuffer Int 但我可以更改 Arr
  • 使用无形类型不等式时如何自定义 Scala 模糊隐式错误

    def typeSafeSum T lt Nat W lt Nat R lt Nat x T y W implicit sum Sum Aux T W R error R 7 x typeSafeSum 3 4 compilation er
  • Scala 中的 Apply 和 lambda

    我有下面的代码 scala gt val builder new StringBuilder foo bar baz builder StringBuilder foo bar baz scala gt 0 until 5 foreach
  • 如何在 akka actor 中测试公共方法?

    我有一个 akka 演员 class MyActor extends Actor def recieve def getCount id String Int do a lot of stuff proccess id do more st
  • 带可变参数的 Spark UDF

    如文档中所示 列出最多 22 个参数是唯一的选择吗 https spark apache org docs 1 5 0 api scala index html org apache spark sql UDFRegistration ht
  • Scala REPL / SBT Console 是否有配置文件?

    我一直在尝试找到某种点文件来放入 Scala REPL 设置和自定义函数 我特别有兴趣传递它的标志 例如 Dscala color 启用语法突出显示 以及覆盖设置 如结果字符串截断 scala gt power scala gt vals
  • Scala 匿名函数中的 return 语句

    为什么显式 return 语句 使用return关键字 在匿名函数中从封闭的命名函数返回 而不仅仅是从匿名函数本身返回 例如 以下程序会导致类型错误 def foo String x Integer gt return x foo 我知道建
  • 相当于 scala 中的 python repr()

    有没有相当于Python的东西reprscala 中的函数 即 您可以给任何 scala 对象提供一个函数 它将生成该对象的字符串表示形式 该对象是有效的 scala 代码 eg val l List Map 1 gt a print re
  • Scala:“递归值...需要类型”,但我只使用 Java 类型

    object Rec extends App val outStream new java io ByteArrayOutputStream val out new java io PrintStream new java io Buffe
  • WSClient - 打开的文件太多

    我正在 CentOS 6 上使用 Play Framework 2 4 我的应用程序抛出此异常 java net SocketException Too many open files 我在 Stack Overflow 上搜索了很多主题并
  • xsbt 插件 1.0.0-M7 和 scalatra

    我尝试在我的 scalatra 项目中将 xsbt 插件升级到 1 0 0 M7 但 scalatra 似乎与此版本不兼容 当我尝试重新加载项目时 出现以下错误 我尝试过 scalatra 2 3 0 版本 问候 德斯 java lang
  • Akka中有轻量级的actor吗?

    我的用例非常简单 在两个对象之间交换少量 现在我正在从 Scala Actors 迁移到 Akka 但是我再也找不到那些轻量级 Actors 使用Akka 我不仅需要为Actor创建创建ActorSystem Props 还需要照顾Acto
  • 比较 javascript 元素和 scala 变量的 Play 框架 Twirl 模板

    如下面的代码示例所示 我想比较 scala 辅助元素内的 javascript 元素 然而 即使存在元素 abcde 它也始终返回 false 除了使用标签之外 如何获取 scala 辅助元素内的 javascript 值 appSeq S
  • Spark scala:大量列上的简单 UDF 会导致性能下降

    我有一个包含 1 亿行和约 10 000 列的数据框 这些列有两种类型 标准 C i 和动态 X i 这个dataframe是经过一些处理后得到的 性能很快 现在只剩下2步了 Goal 需要使用 C i 列的相同子集对每个 X i 执行特定

随机推荐

  • row_array()['key'] 在 PHP 5.3 中不起作用

    我是否正确 以下语法在 PHP 5 4 中有效 但在 PHP 5 3 中无效 users key class class gt row array name The row array function 是一个返回数组的 CodeIgnit
  • 如何从本地主机将 SQL 数据库导入 R?

    我刚刚使用 MAMP 创建了我的第一个 SQL 数据库 很简单 只是一个宠物列表 我想将它加载到 R 中 这是我写的 install packages dbConnect library dbConnect mypets dbConnect
  • 在同一个元素上并行执行多个 jQuery 效果

    我发现这个问题被问了很多次 但没有一个解决方案对我有用 我有两个想要并行执行的效果 我希望盒子同时淡入和弹跳 http jsfiddle net 6VVUG http jsfiddle net 6VVUG 链接 UI 效果并使用dequeu
  • sqflt8、sqlmoney 和其他本机 SQL 数据类型的二进制存储格式是什么?

    根据文档 可以使用以本机 SQL Server 数据格式格式化的 bcp 导入或导出本机 二进制 数据 例如 SQLFLT8 SQLFLT4 SQLMONEY 或 SQLNUMERIC 有谁知道各种类型的数据格式是什么 或者在哪里可以找到指
  • 基于第一个淘汰赛教程,为什么我的代码没有运行?

    我了解教程在页面上的工作原理 但我正在尝试在本地设置一个计算器来创建计算器 但无法让 knockout js 工作 它不像 Knockout js 在线教程那样初始化或填充 HTML
  • 使用pdfbox从pdf中删除不可见文本

    链接到 pdf https drive google com file d 1F8vrzcABwxVGdN5W 7etQggY5xKtGplU view 当我尝试从上面的 pdf 中提取文本时 我得到了在 evince 查看器中不可见的文本
  • QuickFix 发送时间(字段 52)减少毫秒

    我正在使用 Python API 运行 QuickFix 并使用 FIX4 2 连接到 TT FIX 适配器 我已成功登录并发送市场数据请求 回复都很好啊在我的消息日志 屏幕日志和文件日志 中 我收到一个 SendingTime 字段 52
  • 如何恢复 Clearcase 中签出的文件?

    假设有一个名为 myfile java 的文件 我检查了一下并且正在研究它 在检查之前 我丢失了硬盘 必须购买新硬盘 下次我想签出该文件时 它说我无法签出 它已经在已经消失的旧视图中签出 我必须提到我正在使用 重用开发流选项 选项 我可以做
  • 让 DOM IE 变得友好

    我怎样才能使这个脚本对IE友好 唯一对 IE 不友好的部分是变量scrolledtonum and heightofbody function getheight var myWidth 0 myHeight 0 if typeof win
  • 具有可见条件或任务依赖性的 VSTS 构建摘要选项卡

    我尝试将新的自定义选项卡添加到构建结果的摘要页面 但仅针对使用我的自定义构建任务进行的构建添加该选项卡 例如 任务 发布工件 仅当添加此任务时 摘要页面中才会添加 工件 选项卡 我希望我的任务和选项卡具有相同的行为 现在 我刚刚在 贡献 中
  • 无法确定操作系统

    When I go on terminal i installed smlnj and i type sml it gives me the error sml unable to determine architecture operat
  • Bigquery 是否会为通过流式传输插入的每一行保存时间戳?

    我知道 Hbase 在每次插入时都会保存一个时间戳 google BigQuery 也是这样吗 你如何访问它 目前存在解决方法 此功能已经以不同的方式投入生产 如果用户希望在请求到达 BigQuery 流系统时保存时间戳 用户可以在表架构中
  • 变量值更改时中断

    与这里的其他问题类似 像这个 https stackoverflow com questions 3231149 visual studio break on variable change 有没有办法在任何 JavaScript 调试器中
  • pdfmake - 使用自己的字体不起作用

    我正在使用 pdfmake 在客户端创建 PDF 我们有一个所见即所得的编辑器 允许用户创建 pdf 然后对其进行解析以与 pdfmake 一起使用 但是 我无法使用普通字体 该插件使用vfs fonts js https github c
  • 如何在InstallShield中单击按钮打开网页?

    HI 我想通过单击 InstallShield 中创建的任何对话框中的按钮来打开网页 我认为它可以通过使用自定义操作来创建 但由于我是这个工具的新手 没有找到实现此目的的确切方法 如果有人对此有想法 请帮忙 Thanks 就像 epotte
  • 模板非类型参数推导

    是否可以推断出 c 17 函数的模板值 而不是类型 函数 foo template
  • Google 地图 - 资源解释为脚本,但使用 MIME 类型 image/png 进行传输

    我做了一些研究 但找不到专门针对 Google Maps V3 Javascript API 的帖子 因此我发布了一个新问题 如果有更合适的地方来回答这个问题 请告诉我 我的问题 在没有接触任何东西的情况下 我的网站利用 Google Ma
  • iPhone SDK 有合适的 OpenGL 文本绘制库吗?

    我正在尝试找出一种简单的方法来在 OpenGL 中绘制一些文本 我的研究表明这是一项相当复杂的任务 它涉及创建 或在运行时生成 字体图集纹理 然后为每个字母创建一个具有正确位置和纹理坐标的四边形 我听说过一些关于 freetype 的好消息
  • 如何将 Graphics2D 中的图形基元捕获到 SVG 中

    我需要从对 java awt Graphics2D 的调用中捕获图形基元 这些调用是通过开源工具包 Apache 的 PDFBox 进行的 通常在 JPanel 中呈现 我想拦截这些调用并将它们转换为 SVG 以便我可以构建非图形数据模型
  • StringContext 和宏:一个简单的示例

    我正在努力实现一个StringContext扩展名允许我这样写 val tz zone Europe London tz is of type java util TimeZone 但附加的警告是如果提供的时区无效 它应该无法编译 假设可以