自定义字符串插值器
除内置字符串插补器外,还可以定义自定义字符串插值器。
my"foo${bar}baz"
由编译器扩展为:
new scala.StringContext("foo", "baz").my(bar)
scala.StringContext
没有 my
方法,因此它可以通过隐式转换提供。然后将实现与内置 s
插值器具有相同行为的自定义插值器,如下所示:
implicit class MyInterpolator(sc: StringContext) {
def my(subs: Any*): String = {
val pit = sc.parts.iterator
val sit = subs.iterator
// Note parts.length == subs.length + 1
val sb = new java.lang.StringBuilder(pit.next())
while(sit.hasNext) {
sb.append(sit.next().toString)
sb.append(pit.next())
}
sb.toString
}
}
插值 my"foo${bar}baz"
将 desugar:
new MyInterpolation(new StringContext("foo", "baz")).my(bar)
请注意,插值函数的参数或返回类型没有限制。这导致我们走下了一条黑暗的道路,其中可以创造性地使用插值语法来构造任意对象,如以下示例所示:
case class Let(name: Char, value: Int)
implicit class LetInterpolator(sc: StringContext) {
def let(value: Int): Let = Let(sc.parts(0).charAt(0), value)
}
let"a=${4}" // Let(a, 4)
let"b=${"foo"}" // error: type mismatch
let"c=" // error: not enough arguments for method let: (value: Int)Let