受this的启发,我想知道我们是否可以在Scala中使用类型安全的字符串插值(可能使用宏)?
例如,我希望有这样的东西
def a[A] = ???
val greetFormat = f"Hi! My name is ${a[String]}. I am ${a[Int]} years old"
greetFormat.format("Rick", 27) // compiles
//greetFormat.format("Rick", false) // does not compile
//greetFormat.format(27, "Rick") // does not compile
//greetFormat.format("Rick", 27, false) // does not compile
//greetFormat.format("Rick") // does not compile or is curried?
答案 0 :(得分:3)
f
字符串插值器已经用宏实现。
这可以在REPL中证明:
scala> val b = "not a number"
b: String = not a number
scala> f"$b%02d"
<console>:9: error: type mismatch;
found : String
required: Int
f"$b%02d"
^
答案 1 :(得分:2)
将其包装在一个函数中。
def greet(name: String, age: Int) = s"Hi! My name is $name. I am $age years old"
答案 2 :(得分:1)
您可以为f-interpolator提供含义:
scala> case class A(i: Int)
defined class A
scala> implicit def atoi(a: A): Int = a.i
warning: there were 1 feature warning(s); re-run with -feature for details
atoi: (a: A)Int
scala> f"${A(42)}%02d"
res5: String = 42
另请参阅Travis Brown's examples和using regex group names in extractions的解决方案。我花了大约一分钟才能窃取这个好主意。
"a123bc" match {
case res @ xr"(?<c>a)(?<n>\d+)(?<s>bc)" => assert {
res.c == 'a' && res.n == 123 && res.s == "bc"
}
}
为了记录,在构图方面,我想:
val a = A(Rick, 42)
val greeter = f"Hi! My name is $_. I am ${_}%d years old"
greeter(a, a)
但对于可怜的下划线来说,这被认为太多了。您必须像在另一个答案中一样编写该函数。
您的表单,您的宏看到"${a[Int]}"
并使用Int
参数编写函数,并不难以实现。
f-interpolator的其他功能包括其他静态错误检查:
scala> f"$b%.02d"
<console>:19: error: precision not allowed
f"$b%.02d"
^
并支持Formattable
:
scala> val ff = new Formattable { def formatTo(fmtr: Formatter, flags: Int, width: Int, precision: Int) = fmtr.format("%s","hello, world") }
ff: java.util.Formattable = $anon$1@d2e6b0b
scala> f"$ff"
res6: String = hello, world
快速宏可能会发出(i: Int) => f"${ new Formattable {...} }"
。