Scala 动态字符串插值
我想漂亮地打印Scala 动态字符串插值,scala,string-interpolation,Scala,String Interpolation,我想漂亮地打印产品,例如案例类,因此我创建了以下特性: trait X extends Product { def fmtStrs = productIterator map { case _ : Double => "%8.2f" case _ => "%4s" } map (_ + separator) toSeq override def toString = { new StringCon
产品
,例如案例类
,因此我创建了以下特性:
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 for中描述的字符串插值
但这不会编译,有一个神秘的错误:
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"
之所以
f
是一个宏,是因为当格式说明符和参数的类型不匹配时,它会给您一个错误,而这是不可能通过查看(“”+:fmtStrs:*)
和(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)
c.宏应用程序匹配{
//案例q“$\(..$parts).f(..$args)”=>
已应用案例(选择(应用(u,零件),u),u,argss)=>
val args=argss.flatte
def badlyInvoked=(parts.length!=args.length+1)&&true{
def,因为(s:String)=s“插入字符串的参数太多$s”
val(p,msg)=
如果(parts.length==0)(c.prefix.tree.pos,“没有零件”)
否则如果(参数长度+1<零件长度)
(如果(args.isEmpty)c.enclosuringposition else args.last.pos,因为(“很少”))
else(args(parts.length-1).pos,因为(“许多”))
c、 中止(p,msg)
}
if(badly调用)c.macroApplication else插值(部件、参数)
调用时,parts
和argss
中都有一棵树,并且parts.length!=args.length+1
为真,因此badlycalleced
为真
s
不在乎它的参数是什么样子,所以它只是一个方法,你的场景也能工作。相当奇怪的是,如果你把f
插值器改成s
插值器,这看起来很复杂(而且有效)…谢谢;为了记录在案,我们没有使用字符串插值,而是直接调用了java.lang.String.Formatter
。