Что не так с многострочными строками Groovy?

106

Скрипты Groovy вызывают ошибку:

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

Ошибка:

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

Пока этот скрипт работает нормально:

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

Зачем?

Егор256
источник
5
Если это поможет кому-то другому, вы можете получить ту же ошибку с кодом вроде def a = b + + "/" + c. В этом случае, очевидно, проблема заключается в двух символах +.
Джефф Хакворт,

Ответы:

237

Поскольку у Groovy нет маркера EOL (например, ; ), он запутается, если вы поместите оператор в следующую строку

Вместо этого это будет работать:

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

поскольку синтаксический анализатор Groovy знает, что ожидать чего-то в следующей строке

Groovy рассматривает ваш оригинал defкак три отдельных утверждения. Первые правопреемников testк a, второй два раза , чтобы сделать "test"положительный (и это, где это не получится )

С помощью new Stringметода конструктора синтаксический анализатор Groovy все еще находится в конструкторе (поскольку фигурная скобка еще не закрыта), поэтому он может логически объединить три строки в один оператор.

Для настоящих многострочных строк вы также можете использовать тройную кавычку:

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

Создадим строку с тестом на трех строках

Кроме того, вы можете сделать его более аккуратным:

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

stripMarginметод будет обрезать левый (до и включая |символ) из каждой строки

tim_yates
источник
6
Или просто используйте stripIndent () вместо stripMargin().
sschuberth
Да, и опускайте |символы в дополнительных строках
tim_yates
4
Вы можете использовать двойные кавычки внутри """строк
tim_yates
3
Правильно, я отредактировал ответ, чтобы показать, как вам нужно немного переформатировать код, чтобы он заработал stripIndent().
sschuberth
2
Потому что а) я уже опубликовал его как комментарий, и б) он не сильно отличается от этого ответа.
sschuberth
18

Аналогично stripMargin(), вы также можете использовать stripIndent () как

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

Из-за

Строка с наименьшим количеством ведущих пробелов определяет число, которое нужно удалить.

вам также необходимо сделать отступ для первого «теста» и не помещать его сразу после начального """(это \гарантирует, что многострочная строка не начинается с новой строки).

Sschuberth
источник
2
что за \ для?
Джо Филлипс
4
Я улучшил свое последнее предложение, чтобы лучше его объяснить.
sschuberth
17

Вы можете указать Groovy, что оператор должен вычисляться после окончания строки, добавив пару круглых скобок. ( ... )

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

Второй вариант - использовать обратную косую черту \в конце каждой строки:

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

FWIW, это идентично тому, как работают многострочные операторы Python.

cmcginty
источник
Второе - это также то, как работают многострочные операторы VBA: D (Только с подчеркиванием вместо обратной косой черты, потому что VBA.)
Чарльз Вуд
Второй вариант не удался для меня в файле Jenkins. Первый вариант сработал.
SilverJan
Nitpick: многострочная строка Python не требует оператора конкатенации при использовании скобок, поэтому это не совсем то же самое.
Big McLargeHuge