动态字符串插值

时间:2016-11-03 15:12:42

标签: scala string-interpolation

我想打印一个Product,例如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 : _*)
    }
  }

这使用ScalaDoc中描述的字符串插值StringContext

但这不会编译,这个神秘的错误:

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"

1 个答案:

答案 0 :(得分:2)

temp5 = match5.setdefault(query_site, []) temp5.append(match_site) 是一个宏的原因是,当格式说明符和参数的类型不匹配时,它会给你一个错误,这不可能通过查看f来检查和("" +: fmtStrs : _*),所以这不起作用并不特别令人惊讶。错误信息可能更清晰,所以让我们看看到底发生了什么。

如果你看the implementation of f(我花了一些时间才真正找到它,我最后通过搜索错误信息来做到了),你会看到

(productIterator.toSeq : _*)

通过您的通话,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) parts中只有一棵树,argss为真,因此parts.length != args.length + 1为真。

badlyInvoked并不关心它的参数是什么样的,所以它只是一种方法而且你的场景有效。