Co jest nie tak z wieloliniowymi ciągami Groovy?

106

Groovy scripts wywołuje błąd:

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

Błąd:

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

Chociaż ten skrypt działa dobrze:

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

Czemu?

yegor256
źródło
5
Jeśli pomoże to komuś innemu, możesz otrzymać ten sam błąd z kodem, takim jak def a = b + + "/" + c. W tym przypadku problemem są oczywiście dwa symbole +.
Geoff Hackworth

Odpowiedzi:

237

Ponieważ groovy nie ma znacznika EOL (takiego jak ;), jest zdezorientowany, jeśli umieścisz operator w następującej linii

To zadziałałoby zamiast tego:

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

ponieważ parser Groovy wie, że może się spodziewać czegoś w następnym wierszu

Groovy postrzega Twój oryginał defjako trzy oddzielne stwierdzenia. Pierwsze przypisuje testdo a, drugi dwa spróbować zrobić "test"pozytywne (i to jest, gdy nie powiedzie się)

W przypadku new Stringmetody konstruktora parser Groovy nadal znajduje się w konstruktorze (ponieważ nawias nie został jeszcze zamknięty), więc może logicznie połączyć trzy wiersze w jedną instrukcję

W przypadku prawdziwych ciągów wielowierszowych możesz również użyć potrójnego cudzysłowu:

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

Stworzy łańcuch z testem w trzech liniach

Możesz również uczynić to schludniejszym, wykonując:

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

stripMarginsposób będzie wykończenia lewo (aż do i włączając |znaki) z każdej linii

tim_yates
źródło
6
Lub po prostu użyj stripIndent () zamiast stripMargin().
sschuberth
Tak, i pomiń |znaki w dodatkowych wierszach
tim_yates,
4
Możesz używać podwójnych cudzysłowów wewnątrz """ciągów znaków
tim_yates,
3
Dobrze, zredagowałem odpowiedź, aby pokazać, jak trzeba nieco przeformatować kod, aby stripIndent()działał.
sschuberth
2
Ponieważ a) zamieściłem to już jako komentarz, b) nie różni się zbytnio od tej odpowiedzi.
sschuberth
18

Podobnie stripMargin(), możesz również użyć stripIndent () jak

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

Z powodu

Linia z najmniejszą liczbą początkowych spacji określa liczbę do usunięcia.

musisz również wciąć pierwszy "test" i nie umieszczać go bezpośrednio po initalu """( \zapewnia, że ​​wieloliniowy ciąg nie zaczyna się od nowej linii).

sschuberth
źródło
2
do czego służy \?
Joe Phillips
4
Poprawiłem moje ostatnie zdanie, żeby lepiej to wyjaśnić.
sschuberth
17

Możesz powiedzieć Groovy'emu, że instrukcja powinna być oceniana poza końcem wiersza, dodając parę nawiasów ( ... )

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

Drugą opcją jest użycie odwrotnego ukośnika \na końcu każdego wiersza:

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

FWIW, jest to identyczne z działaniem instrukcji wielowierszowych Pythona.

cmcginty
źródło
Drugi to również sposób działania instrukcji wielowierszowych VBA: D (Tylko z podkreśleniami zamiast ukośników odwrotnych, ponieważ VBA.)
Charles Wood
Druga opcja zawiodła dla mnie w pliku Jenkinsfile. Pierwsza opcja zadziałała.
SilverJan
Nitpick: Wieloliniowy ciąg znaków Pythona nie wymaga operatora konkatenacji podczas korzystania z paren, więc nie jest dokładnie taki sam.
Big McLargeHuge