Interpolación de cadenas en Scala 2.10 – ¿Cómo interpolar una variable String?

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 comstack, 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 comstackción diferente al no encontrado , creo)


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 comstackdor 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 comstackdor elige el nombre y se lo da al método. Dado que esto sucede en tiempo de comstackción, no puede hacerlo de forma sensata de forma dinámica: el comstackdor 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á progtwigdo 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.

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 =  val message = template(name) //> message: String = Hello World 
  1. La interpolación de cadenas ocurre en tiempo de comstackción, por lo que el comstackdor 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 comstackció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 = { ... } } 

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í).

    Intereting Posts