¿Qué pasa con Groovy multilínea String?

105

Groovy scripts genera un error:

def a = "test"
  + "test"
  + "test"

Error:

No signature of method: java.lang.String.positive() is 
applicable for argument types: () values: []

Si bien este script funciona bien:

def a = new String(
  "test"
  + "test"
  + "test"
)

¿Por qué?

yegor256
fuente
5
En caso de que ayude a alguien más, puede obtener el mismo error con un código como def a = b + + "/" + c. En este caso, los dos símbolos + son obviamente el problema.
Geoff Hackworth

Respuestas:

236

Como groovy no tiene marcador EOL (como ;), se confunde si coloca el operador en la siguiente línea

Esto funcionaría en su lugar:

def a = "test" +
  "test" +
  "test"

ya que el analizador Groovy sabe esperar algo en la siguiente línea

Groovy ve tu original defcomo tres declaraciones separadas. Los primeros cesionarios testa a, los dos segundos tratan de hacer "test"positivo (y aquí es donde se produce un error)

Con el new Stringmétodo del constructor, el analizador Groovy todavía está en el constructor (ya que la llave aún no se ha cerrado), por lo que lógicamente puede unir las tres líneas en una sola declaración.

Para verdaderas cadenas de varias líneas, también puede usar la comilla triple:

def a = """test
test
test"""

Creará una cadena con prueba en tres líneas

Además, puede hacerlo más ordenado:

def a = """test
          |test
          |test""".stripMargin()

el stripMarginmétodo recortará la izquierda (hasta e incluyendo el |carácter) de cada línea

tim_yates
fuente
6
O simplemente use stripIndent () en lugar de stripMargin().
sschuberth
Sí, y omita los |caracteres en las líneas adicionales
tim_yates
4
Puede usar comillas dobles dentro de """cadenas
tim_yates
3
Correcto, he editado la respuesta para mostrar cómo necesitaría reformatear ligeramente el código para que stripIndent()funcione.
sschuberth
2
Porque a) ya lo había publicado como comentario yb) no es muy diferente de esta respuesta.
sschuberth
17

Puede decirle a Groovy que la declaración debe evaluarse más allá de la línea que termina agregando un par de paréntesis ( ... )

def a = ("test"
  + "test"
  + "test")

Una segunda opción es usar una barra invertida \, al final de cada línea:

def a = "test" \
  + "test" \
  + "test"

FWIW, esto es idéntico a cómo funcionan las declaraciones de múltiples líneas de Python.

cmcginty
fuente
El segundo es también cómo VBA declaraciones de varias líneas de trabajo: D (Sólo con guiones en lugar de barras invertidas, porque VBA.)
Charles Wood
La segunda opción me falló en un archivo Jenkins. La primera opción funcionó.
SilverJan
Nitpick: la cadena de varias líneas de Python no requiere el operador de concatenación cuando se usa parens, por lo que no es exactamente lo mismo.
Big McLargeHuge
17

Similar a stripMargin(), también puede usar stripIndent () como

def a = """\
        test
        test
        test""".stripIndent()

Porque

La línea con el menor número de espacios iniciales determina el número que se eliminará.

también necesita sangrar la primera "prueba" y no ponerla directamente después de la inicial """(esto \asegura que la cadena de varias líneas no comience con una nueva línea).

sschuberth
fuente
2
para que es el \?
Joe Phillips
4
He mejorado mi última frase para explicarla mejor.
sschuberth