Получить имена аргументов в интерполяции строк в Scala 2.10

Начиная со scala 2.10 возможна следующая интерполяция.

val name = "someName"
val interpolated = s"Hello world, my name is $name"

Теперь также возможно определить пользовательские интерполяции строк, как вы можете видеть в документации scala в разделе «Расширенное использование» здесь http://docs.scala-lang.org/overviews/core/string-interpolation..html#advanced_usage

Итак, мой вопрос: есть ли способ получить исходную строку перед интерполяцией, включая любые интерполированные имена переменных, из неявного класса, определяющего новую интерполяцию для строк?

Другими словами, я хочу иметь возможность определить интерполяцию x таким образом, чтобы при вызове

x"My interpolated string has a $name"

я могу получить строку точно так, как показано выше, без замены части $name внутри интерполяции.

Изменить: вкратце, причина, по которой я хочу это сделать, заключается в том, что я хочу получить исходную строку и заменить ее другой строкой, интернационализированной строкой, а затем заменить значения переменных. Это основная причина, по которой я хочу получить исходную строку без интерполяции.

Заранее спасибо.


person Angel Blanco    schedule 11.02.2013    source источник
comment
Каков ваш вариант использования? Возможно, есть лучшее решение, чем использование интерполяции строк, которая является довольно специфической конструкцией.   -  person EECOLOR    schedule 12.02.2013


Ответы (3)


Поскольку интерполяция строк Scala может обрабатывать произвольные выражения в пределах ${}, она должна вычислять аргументы перед передачей их в функцию форматирования. Таким образом, прямой доступ к именам переменных невозможен по замыслу. Как указал Юджин, можно получить имя простой переменной с помощью макросов. Однако я не думаю, что это очень масштабируемое решение. В конце концов, вы потеряете возможность вычислять произвольные выражения. Что, например, будет в этом случае:

x"My interpolated string has a ${"Mr. " + name}"

Возможно, вы сможете извлечь имя переменной с помощью макросов, но это может быть сложно для произвольных выражений. Мои предложения: Если имя вашей переменной должно иметь смысл в интерполяции строк, сделайте его частью структуры данных. Например, вы можете сделать следующее:

case class NamedValue(variableName: String, value: Any)

val name = NamedValue("name", "Some Name")

x"My interpolated string has a $name"

Объекты передаются как Any* в x. Таким образом, теперь вы можете сопоставлять NamedValue внутри x и можете делать определенные вещи в зависимости от «имени переменной», которое теперь является частью вашей структуры данных. Вместо явного сохранения имени переменной вы также можете использовать иерархию типов, например:

sealed trait InterpolationType
case class InterpolationTypeName(name: String) extends InterpolationType
case class InterpolationTypeDate(date: String) extends InterpolationType

val name = InterpolationTypeName("Someone")
val date = InterpolationTypeDate("2013-02-13")
x"$name is born on $date"

Опять же, в x вы можете сопоставить подтип InterpolationType и обрабатывать вещи в соответствии с типом.

person bluenote10    schedule 13.02.2013
comment
Спасибо! Это было отличное объяснение, и вы предлагаете элегантную альтернативу. Попробую это :) - person Angel Blanco; 19.02.2013

Кажется, это невозможно. Интерполяция строк выглядит как функция компиляции, которая компилирует пример в:

StringContext("My interpolated string has a ").x(name)

Как видите, части $name уже нет. Мне стало действительно ясно, когда я посмотрел исходный код StringContext: https://github.com/scala/scala/blob/v2.10.0/src/library/scala/StringContext.scala#L1

person EECOLOR    schedule 11.02.2013

Если вы определите x как макрос, вы сможете увидеть дерево дешугаринга, созданное компилятором (как показано @EECOLOR). В этом дереве аргумент "имя" будет отображаться как Ident(newTermName("name")), так что вы сможете извлечь оттуда имя. Обязательно ознакомьтесь с руководствами по макросам и рефлексии на docs.scala-lang.org, чтобы узнать, как писать макросы и работать с деревьями.

person Eugene Burmako    schedule 12.02.2013