Quel est le problème avec la chaîne multi-lignes Groovy?

105

Les scripts Groovy soulèvent une erreur:

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

Erreur:

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

Bien que ce script fonctionne correctement:

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

Pourquoi?

yegor256
la source
5
Si cela aide quelqu'un d'autre, vous pouvez obtenir la même erreur avec un code comme def a = b + + "/" + c. Dans ce cas, les deux symboles + sont évidemment le problème.
Geoff Hackworth

Réponses:

236

Comme groovy n'a pas de marqueur EOL (tel que ;), il devient confus si vous mettez l'opérateur sur la ligne suivante

Cela fonctionnerait à la place:

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

comme l'analyseur Groovy sait s'attendre à quelque chose sur la ligne suivante

Groovy considère votre original defcomme trois déclarations distinctes. Le premier assigne testà a, les deux seconds essaient de rendre "test"positif (et c'est là que ça échoue)

Avec la new Stringméthode constructeur, l'analyseur Groovy est toujours dans le constructeur (car l'accolade n'est pas encore fermée), il peut donc logiquement joindre les trois lignes en une seule instruction

Pour les vraies chaînes multi-lignes, vous pouvez également utiliser le guillemet triple:

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

Créera une chaîne avec test sur trois lignes

En outre, vous pouvez le rendre plus net en:

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

la stripMarginméthode coupera la gauche (jusqu'à et y compris le caractère |) de chaque ligne

tim_yates
la source
6
Ou utilisez simplement stripIndent () au lieu de stripMargin().
sschuberth
Ouais, et omettez les |caractères sur les lignes supplémentaires
tim_yates
4
Vous pouvez utiliser des guillemets doubles à l'intérieur des """chaînes
tim_yates
3
Bon, j'ai édité la réponse pour montrer comment vous auriez besoin de reformater légèrement le code pour stripIndent()fonctionner.
sschuberth
2
Parce que a) je l'avais déjà posté en commentaire, et b) ce n'est pas très différent de cette réponse.
sschuberth
18

Similaire à stripMargin(), vous pouvez également utiliser stripIndent () comme

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

En raison de

La ligne avec le moins d'espaces de début détermine le nombre à supprimer.

vous devez également indenter le premier "test" et ne pas le mettre directement après l'initial """(cela \garantit que la chaîne multiligne ne commence pas par une nouvelle ligne).

sschuberth
la source
2
quel est le \ pour?
Joe Phillips
4
J'ai amélioré ma dernière phrase pour mieux l'expliquer.
sschuberth
17

Vous pouvez dire à Groovy que l'instruction doit évaluer au-delà de la fin de la ligne en ajoutant une paire de parenthèses ( ... )

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

Une deuxième option consiste à utiliser une barre oblique inverse,, \à la fin de chaque ligne:

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

FWIW, ceci est identique au fonctionnement des instructions multilignes Python.

cmcginty
la source
Le second est également le fonctionnement des instructions multilignes VBA: D (Uniquement avec des traits de soulignement au lieu de barres obliques inverses, car VBA.)
Charles Wood
La deuxième option a échoué pour moi dans un Jenkinsfile. La première option a fonctionné.
SilverJan
Nitpick: La chaîne multiligne Python ne nécessite pas l'opérateur de concaténation lors de l'utilisation de parens, donc ce n'est pas exactement la même chose.
Big McLarge énorme