动态字符串插值

卢西亚诺

我想漂亮地打印a Product,例如a case class,所以我创建了以下特征:

  trait X extends Product {
    def fmtStrs =
      productIterator map {
        case _ : Double => "%8.2f"
        case _ => "%4s"
      } map (_ + separator) toSeq
    override def toString = {
      new StringContext("" +: fmtStrs : _*) f (productIterator.toSeq : _*)
    }
  }

StringContext的ScalaDoc中所述,这将使用字符串插值

但这不会编译,并出现以下神秘错误:

Error:(69, 70) too many arguments for interpolated string
      new StringContext("" +: fmtStrs : _*) f (productIterator.toSeq : _*)

这是错误还是宏的限制?请注意,执行以下操作可以正常工作,因此我怀疑这可能与变量参数列表有关:

scala> val str2 = StringContext("","%4s,","%8.2f").f(1,23.4)
str2: String = "   1,   23.40"
阿列克谢·罗曼诺夫(Alexey Romanov)

原因f是宏,因此当格式说明符和参数的类型不匹配时,它会给您一个错误,并且无法通过查看("" +: fmtStrs : _*)来检查(productIterator.toSeq : _*),因此,这样做并不奇怪。工作。错误消息可能更清晰,所以让我们看看到底发生了什么。

如果您查看的实现f(花了我一些时间才能真正找到它,我终于通过搜索错误消息来做到了),您将看到:。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。.。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。((()。。。。。的关键词的信息。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

c.macroApplication match {
  //case q"$_(..$parts).f(..$args)" => 
  case Applied(Select(Apply(_, parts), _), _, argss) => 
    val args = argss.flatten
    def badlyInvoked = (parts.length != args.length + 1) && truly {
      def because(s: String) = s"too $s arguments for interpolated string"
      val (p, msg) =
        if (parts.length == 0) (c.prefix.tree.pos, "there are no parts")
        else if (args.length + 1 < parts.length)
          (if (args.isEmpty) c.enclosingPosition else args.last.pos, because("few"))
        else (args(parts.length-1).pos, because("many"))
      c.abort(p, msg)
    }
    if (badlyInvoked) c.macroApplication else interpolated(parts, args)

有了你的电话,你有一棵树在这两个partsargss,和parts.length != args.length + 1是真实的,所以badlyInvoked是真实的。

s 不在乎其参数是什么样,因此它只是一种方法,您的方案可以工作。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章