bytes.Buffer и strings.Builder
Зачем это на интервью
Конкатенация строк в цикле может создавать много промежуточных строк. Правильный builder уменьшает аллокации, а bytes.Buffer нужен, когда API работает с байтами или io.Reader/io.Writer.
Минимум для E4
- Выбирать
strings.Builderдля построения строки иbytes.Bufferдля байтов/I/O. - Вызывать
Growтолько как оптимизацию после измерения или при известном размере. - Не копировать ненулевой
BuilderиBuffer.
Углубление для E5/Senior
strings.Builder имеет API записи строк/байтов и String; он не реализует чтение. bytes.Buffer — растущий буфер байт, реализует Reader и Writer, пригоден для кодеков и потокового API. После String/Bytes не сохраняйте результат, если буфер будет переиспользован, без понимания aliasing и документации метода. Reset сохраняет выделенную capacity: это полезно в ограниченном lifecycle, но удерживает большой пик памяти.
Ключевые понятия
func greeting(names []string) string {
var b strings.Builder
b.Grow(len("hello: ") + len(names)*8)
b.WriteString("hello: ")
for i, name := range names {
if i > 0 { b.WriteString(", ") }
b.WriteString(name)
}
return b.String()
}
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(map[string]int{"ok": 1}); err != nil { panic(err) }
body := buf.Bytes() // валиден до следующей изменяющей операции с bufНе используйте fmt.Sprintf в каждом витке простого цикла лишь для склейки: это часто дороже и менее явно. Внешний API важнее микрооптимизации: возвращайте string/[]byte, а не mutable buffer.
Типовые вопросы
- Когда нужен
strings.Builder?- При последовательной сборке строки, особенно в цикле.
- Чем Buffer отличается от Builder?
- Buffer работает с
[]byteи I/O; Builder ориентирован на string.
- Buffer работает с
- Можно ли копировать builder после записи?
- Нет; документация запрещает копировать ненулевое значение.
- Что делает
Grow?- Резервирует минимум места; не меняет длину и может panic при слишком большом размере.
- Освобождает ли
Resetпамять?- Он сбрасывает содержимое, но capacity обычно остаётся для повторного использования.
Практика
- Перепишите конкатенацию в цикле через
strings.Builder. Готово: тест идентичен, benchmark с-benchmemсравнивает обе версии. - Закодируйте JSON в
bytes.Buffer. Готово: ошибка Encoder обработана, а тест декодирует результат обратно.
Частые ошибки и ловушки
- Копировать buffer/builder после первого использования.
- Удерживать
Bytes()и затем переиспользовать buffer. - Пулить большие буферы без лимита и удерживать peak memory.
Связанные темы
Коллекции и работа с данными · JSON