Interpolación de cadenas en Scala 2.10-¿Cómo interpolar una variable de cadena?


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 manera de hacer interpolación dinámica, por ejemplo, lo siguiente (no compila, solo con 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 una manera de evaluar" dinámicamente " una cadena como esa? (o es inherentemente incorrecto / no es posible)

  2. ¿Y qué es s 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 que no encontrado Creo)


Author: Suma, 2012-11-07

4 answers

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 desugar en

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

Por defecto, StringContext te da s, f, y raw * métodos.

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

Puede usar vars, sin embargo, para que pueda intercambiar los valores que desee. Y el método predeterminado s solo 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 arreglado hasta 2.10.1; solo el texto antes de una variable es realmente raw (sin procesamiento de escape). Así que espere en el uso de que uno hasta 2.10.1 es fuera, o mirar el código fuente y definir su propio. De forma predeterminada, no hay procesamiento de escape, por lo que definir el suyo es bastante fácil.

 32
Author: Rex Kerr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-07 09:31:44

Aquí hay una posible solución a #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
 10
Author: Eran Medan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-07 01:29:18
  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). Se espera un literal de cadena, de acuerdo con el SIP.
  2. Bajo Advanced Usage en la documentación que enlazó, se explica que una expresión de la forma id"Hello $name ." se traduce en tiempo de compilación a 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. Documentación da un ejemplo para un interpolador json,

implicit class JsonHelper(val sc: StringContext) extends AnyVal {
  def json(args: Any*): JSONObject = {
    ...
  }
}
 7
Author: Kipton Barros,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-07 00:00:22

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

 1
Author: jsalvata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-07 00:17:25