Тип безопасной строковой интерполяции в Scala
Вдохновленный этим, мне было интересно, можем ли мы иметь безопасную для типов интерполяцию строк в 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?
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"
^
Просто оберните это в функцию.
def greet(name: String, age: Int) = s"Hi! My name is $name. I am $age years old"
Вы можете предоставить импликации для f-интерполятора:
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
См. Также примеры и решение Трэвиса Брауна для использования имен групп регулярных выражений в извлечениях. Мне понадобилось около минуты, чтобы украсть эту прекрасную идею.
"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
param, не выглядит сложным для реализации.
Другие функции f-интерполятора включают в себя другую статическую проверку ошибок:
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 {...} }"
,