如何参数化StringContext使用的格式字符串?

时间:2019-03-21 15:23:46

标签: scala formatting scala-macros

假设我有这样的代码行:

log.info(f"$name%-20s $amt%7.2f")

我想要做的是使20name的宽度)本身可以被参数化。我该怎么办?

如果我还想同时设置7.2的{​​{1}}宽度怎么办?有可能吗?

[编辑:我希望将amt20之类的变量放入变量中,以便不会将它们硬编码为格式字符串。]

我已经尝试过直接使用7.2,但似乎我不明白正在发生什么宏扩展:

StringContext

3 个答案:

答案 0 :(得分:1)

您离真相不远:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace PTS.Models
{
    public class Talk
    {
        [Key]
        public int PubId { get; set; }
        public string Title { get; set; }
        public string Category { get; set; }

    }
 }

产量:

val amt= 1234.1234d val name = "James" println(f"|$name%20s $amt%7.2f|")

关于将20和7.2作为参数传递:模板可以生成为:

|               James 1234,12|

产生: val len = 20 val prec = 7.2 val template = s"$$name%${len}s $$amt%${prec}f"

但是字符串内插似乎并不是解决方案,因为即使将其插入到StringContext中,它也是在编译时完成的,然后 $name%20 $amt%7.2f 产生s"$template

我想我可以使用另一种语言

答案 1 :(得分:1)

您可以实现自己的StringContext
注意:# I think '.rxt' is a typo for '.txt' def recursive_unlink(dirname): for entry in os.scandir(dirname): if entry.is_dir(): recursive_unlink(os.path.abspath(entry)) elif entry.name.endswith('.txt'): os.unlink(os.path.abspath(entry)) recursive_unlink('h:') s"a=${a},b=${b}"

StringContext("a=",",b=").s(a,b)

//测试

case class Format(t: String)

// this implement is not type safe in Compile time,
implicit class MyFormat(val sc: StringContext) {

  def myFormat(args: Any*) = {
    val partIter = sc.parts.iterator
    var stringFormatArgs = List.empty[Object]
    val sb = new StringBuilder(partIter.next())

    def impl(list: List[Any]): Unit = {
      list match {
        case (_: Format) :: tail                  =>
          throw new Exception("")
        case (any: Object) :: (format: Format) :: tail =>
          sb.append(partIter.next()).append(format.t).append(partIter.next())
          stringFormatArgs = any :: stringFormatArgs
          impl(tail)
        case (any: Any) :: tail                        =>
          sb.append(any.toString).append(partIter.next())
          impl(tail)
        case Nil                                       =>
      }
    }

    impl(args.toList)
    String.format(sb.toString(), stringFormatArgs.reverse: _*)
  }
}

答案 2 :(得分:1)

您可以分为两个部分。

val name = "Jan"
val nLen = -10  //name length

val amt = 1.1
val ff = 5.3  //float format

s"%${nLen}s".format(name) + s"%${ff}f".format(amt)
//res0: String = Jan       1.100

或一次通过。

s"%${nLen}s%${ff}f".format(name, amt)
//res1: String = Jan       1.100