動的文字列補間

ルチアーノ

私はかなり-印刷したい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 forStringContextで説明されている文字列補間を使用します

しかし、これはコンパイルされず、この不可解なエラーが発生します:

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 : _*)それは特に驚くべきことではない、これがないので、作業。エラーメッセージはより明確になる可能性があるので、正確に何が起こるか見てみましょう。

の実装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

関連記事