Avatar ·

Как правильно писать многострочные строки в Go?

Всем привет! Я только начал изучать Go после Python и столкнулся с проблемой при работе с длинными строками. В Python я привык использовать тройные кавычки для многострочных строк, например: ```python text = """Это многострочная строка в Python, она сохраняет переносы.""" ``` Но в Go я не могу найти аналог. Пытался написать так: ```go package main import "fmt" func main() { text := "Это строка продолжается на новой строке" fmt.Println(text) } ``` И получил ошибку компиляции: `invalid syntax: unexpected newline in string literal`. Как правильно объявить строку, которая занимает несколько строк в коде? Нужно ли использовать какие-то специальные символы или функции? Особенно интересует случай, когда строка содержит HTML, SQL-запросы или JSON — их неудобно писать в одну строку. Пробовал экранировать символ `\n`, но это не решает проблему читаемости. Есть ли в Go что-то вроде heredoc или raw string literals? Заранее спасибо за помощь! <<>>

Использование raw string literals (необработанных строковых литералов)

В Go для многострочных строк используется специальный синтаксис — raw string literals (сырые строки). Они заключаются в обратные кавычки (backticks) `...`, а не в двойные кавычки. Внутри таких строк не работают escape-последовательности (например, \n превращается в буквальные символы обратной косой черты и 'n'), и они могут содержать переносы строк без дополнительного экранирования.

Вот как выглядит решение вашей проблемы:

package main

import "fmt"

func main() {
    text := `Это строка
продолжается на новой строке
и ещё на одной`
    fmt.Println(text)
}

Вывод:

Это строка
продолжается на новой строке
и ещё на одной

Обратите внимание: все пробелы и переносы строк внутри обратных кавычек сохраняются буквально. Если вам нужно начать строку с новой позиции, вы должны управлять отступами вручную.

Пример с SQL-запросом

query := `
    SELECT id, name, email
    FROM users
    WHERE active = true
    ORDER BY name
`

Но будьте осторожны: этот запрос будет содержать лишние пробелы и переносы строк в начале и конце. Для SQL это обычно безопасно, но если нужна чистая строка, используйте конкатенацию или strings.TrimSpace.

Пример с JSON

jsonData := `{
    "name": "Alice",
    "age": 30,
    "city": "New York"
}`

Ограничения raw string literals

  • Нельзя использовать обратные кавычки внутри строки — это вызовет ошибку компиляции. Если вам нужен символ обратной кавычки, придётся использовать конкатенацию или обычные строки с экранированием.
  • Нет escape-последовательностей — например, \t не будет работать как табуляция, а превратится в буквальные символы.

Альтернатива: конкатенация строк

Если вам нужно смешивать escape-последовательности и многострочность, используйте конкатенацию с оператором +:

text := "Строка с табуляцией:\t" +
    "продолжение на новой строке\n" +
    "и ещё одна строка"

Но такой подход менее удобен для больших блоков текста.

Использование strings.Join для списков

Если у вас есть массив строк, их можно объединить:

lines := []string{
    "Первая строка",
    "Вторая строка",
    "Третья строка",
}
text := strings.Join(lines, "\n")

Этот метод особенно полезен, когда строки формируются динамически.

Вывод: для большинства случаев многострочных строк в Go используйте обратные кавычки. Они читаемы, просты и соответствуют духу языка. Для сложных случаев с экранированием — комбинируйте с конкатенацией или strings.

<<>>

Дополнительный совет: обработка отступов в raw string literals

Когда вы пишете многострочную строку внутри функции, часто возникает проблема с отступами. Например:

func main() {
    text := `
        SELECT id, name
        FROM users
    `
    fmt.Println(text) // Содержит лишние пробелы в начале каждой строки
}

Чтобы избежать этого, можно использовать трюк с strings.TrimSpace и strings.ReplaceAll:

import "strings"

func main() {
    raw := `
        SELECT id, name
        FROM users
        WHERE active = true
    `
    // Удаляем ведущие пробелы и переносы по краям
    query := strings.TrimSpace(raw)
    // Заменяем двойные переносы на одинарные (если нужно)
    query = strings.ReplaceAll(query, "\n    ", "\n")
    fmt.Println(query)
}

Но это костыль. Лучше использовать пакет text/template или fmt.Sprintf для сложных случаев. Ещё один вариант — написать строку без отступов и выровнять её визуально с помощью комментариев:

query := `SELECT id, name
FROM users
WHERE active = true`

Такой подход сохраняет читаемость и не требует постобработки.