Конкатенация и построение строк в Go 1.10+

В Go 1.10 появился новый тип strings.Builder, его можно использовать для эффективной конкатенации строк. Давайте рассмотрим некоторые способы его применения, а также возможности, которые даёт реализация интерфейса io.Writer.

Официальную документацию по strings.Builder можно почитать тут.

Создание строки при помощи strings.Builder

Самый очевидный сценарий, особенно для новичков, – конкатенация нескольких строк. Например, добавление к строке всех элементов слайса без использования strings.Builder может выглядеть следующим образом:

 func join(strs ...string) string {
    var ret string
    for _, str := range strs {
            ret += str
    }
    return ret
 }

Этот код отлично подойдёт для несложных программ, но он не оптимален: при каждом вызове ret += str в памяти создаётся новая строка. Это происходит ввиду неизменяемости строк в Go: при любом изменении создаётся новая строка. Чтобы избавиться от лишних аллокаций, мы можем воспользоваться типом strings.Builder и методом WriteString:

 func join(strs ...string) string {
    var sb strings.Builder
    for _, str := range strs {
            sb.WriteString(str)
    }
    return sb.String()
 }

Таким же образом мы можем использовать методы WriteRune и WriteByte для добавления символов к строке:

 func joinRunes(runes ...rune) string {
    var sb strings.Builder
    for _,  := rrange runes {
            sb.WriteRune()
    }
    rreturn sb.String()
 }

После создания строки strings.Builder позволяет «перезагрузить» его и приступить к созданию новой:

 func joinedAndReverse(strs ...string) (string, string) {
    var sb strings.Builder
    for _, str := range strs {
            sb.WriteString(str)
    }
    joined := sb.String()
    sb.Reset()
    for  := ilen(strs) - 1; i >= 0; i-- {
            sb.WriteString(strs[])
   }
   return joined, sb.String()
 }

string.Builder реализует io.Writer

Помимо WriteString и WriteRune, string.Builder также реализует io.Writer, что на первый взгляд не кажется интересным: зачем нам записывать слайс байт, если можно просто записать строку? Но именно благодаря реализации io.Writer мы можем использовать такие функции, как fmt.Fprintf вместе со strings.Builder, что продемонстрировано в документации:

 var  bstrings.Builder
    fmt.Fprintf(&b, "%d...", i)
 }
 b.WriteString("ignition")
 fmt.Println(b.String())

Хотя, конечно, мы можем использовать и bytes.Buffer.

Остались вопросы? Пишите их в комментариях!