varias strings lineas interpolated interpolacion ecmascript concatenar cadenas scala scala-2.10 string-interpolation

scala - strings - string format interpolation java



Interpolación de cadenas en Scala 2.10-¿Cómo interpolar una variable String? (4)

La interpolación de cadenas está disponible en Scala a partir de Scala 2.10

Este es el ejemplo básico

val name = "World" //> name : String = World val message = s"Hello $name" //> message : String = Hello World

Me preguntaba si hay una forma de hacer la interpolación dinámica, por ejemplo, la siguiente (no compila, solo para fines ilustrativos)

val name = "World" //> name : String = World val template = "Hello $name" //> template : String = Hello $name //just for illustration: val message = s(template) //> doesn''t compile (not found: value s)

  1. ¿Hay alguna forma de evaluar "dinámicamente" una cadena así? (o es inherentemente incorrecto / no es posible)

  2. Y que es exactamente? no es un método def ( aparentemente es un método en StringContext ), y no un objeto (si lo fuera, habría arrojado un error de compilación diferente al no encontrado , creo)


  1. La interpolación de cadenas ocurre en tiempo de compilación, por lo que el compilador generalmente no tiene suficiente información para interpolar s(str) . Espera una cadena literal, de acuerdo con el SIP .
  2. En Uso avanzado en la documentación que vinculó, se explica que una expresión del id"Hello $name ." formulario id"Hello $name ." se traduce en tiempo de compilación al new StringContext("Hello", "."). id(name) new StringContext("Hello", "."). id(name) .

Tenga en cuenta que id puede ser un interpolador definido por el usuario introducido a través de una clase implícita. La documentación proporciona un ejemplo para un interpolador json ,

implicit class JsonHelper(val sc: StringContext) extends AnyVal { def json(args: Any*): JSONObject = { ... } }


Aquí hay una posible solución al # 1 en el contexto de la pregunta original basada en la excelente respuesta de Rex

val name = "World" //> name: String = World val template = name=>s"Hello $name" //> template: Seq[Any]=>String = <function1> val message = template(name) //> message: String = Hello World


Esto es intrínsecamente imposible en la implementación actual: los nombres de las variables locales no están disponibles en el momento de la ejecución; pueden mantenerse como símbolos de depuración, pero también pueden haberse eliminado. (Los nombres de las variables de los miembros son, pero eso no es lo que está describiendo aquí).


s es en realidad un método en StringContext (o algo que se puede convertir implícitamente de StringContext ). Cuando escribes

whatever"Here is text $identifier and more text"

el compilador lo desengrasa en

StringContext("Here is text ", " and more text").whatever(identifier)

De forma predeterminada, StringContext le brinda los StringContext s , f y raw *.

Como puede ver, el compilador elige el nombre y se lo da al método. Dado que esto sucede en tiempo de compilación, no puede hacerlo de forma sensata de forma dinámica: el compilador no tiene información sobre nombres de variables en tiempo de ejecución.

Sin embargo, puede usar vars para intercambiar los valores que desee. Y el método predeterminado s simplemente llama a toString (como era de esperar) para que pueda jugar juegos como

class PrintCounter { var i = 0 override def toString = { val ans = i.toString; i += 1; ans } } val pc = new PrintCounter def pr[A](a: A) { println(s"$pc: $a") } scala> List("salmon","herring").foreach(pr) 1: salmon 2: herring

(0 ya fue llamado por el REPL en este ejemplo).

Eso es lo mejor que puedes hacer.

* raw está roto y no está programado para ser reparado hasta 2.10.1; solo el texto antes de que una variable esté realmente en bruto (sin proceso de escape). Así que espere usando eso hasta que 2.10.1 esté fuera, o mire el código fuente y defina el suyo. Por defecto, no hay un proceso de escape, por lo que definir el tuyo es bastante fácil.