Тип безопасной строковой интерполяции в 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 {...} }",

Другие вопросы по тегам