How do you build strings efficiently? Compare +, fmt.Sprintf, bytes.Buffer and strings.Builder.
Question 69MediumGo 1.22 to 1.25
Because strings are immutable, s += x in a loop allocates a new string and copies everything built so far each time, which is O(n²). The options compare like this:
+works for a fixed, small number of pieces. The compiler mergesa + b + cinto one allocation.fmt.Sprintfis convenient but slow: it uses reflection and boxes arguments in interfaces.strings.Joinis best when you already have a[]string. It computes the total size and allocates once.strings.Builderis best for building incrementally. ItsString()method returns the internal[]byteas a string without copying, usingunsafe.String. That is safe because the Builder only ever appends.bytes.Bufferis a read/write buffer that implementsio.Reader. ItsString()copies.
func join(parts []string) string {
var b strings.Builder
n := 0
for _, p := range parts {
n += len(p) + 1
}
b.Grow(n) // single allocation
for i, p := range parts {
if i > 0 {
b.WriteByte(',')
}
b.WriteString(p)
}
return b.String()
}
// Gotcha: copying a non-zero Builder panics on the next write
var b1 strings.Builder
b1.WriteString("x")
b2 := b1 // copy
// b2.WriteString("y") // panic: strings: illegal use of non-zero Builder copied by value
_ = b2
A Builder stores a pointer to itself (addr) to detect copies. A copy would share the byte slice, and appends through two headers would break the zero-copy guarantee. Always pass *strings.Builder. Also use strconv.AppendInt or fmt.Fprintf(&b, ...) rather than Sprintf followed by WriteString.
More on Arrays, Slices, Maps & Strings
- Q67Why are strings immutable in Go, and what does converting between string and []byte cost?
- Q68What does this print? (len, indexing and ranging over a UTF-8 string)
- Q70How do you convert between []byte and string without copying, and what are the risks?
- Q71How do you implement a set in Go, and what maps package helpers exist?
- Q72What does this print before and after Go 1.22? (taking &v and capturing i in loops)
- Q73What does this print? (map of slices built from a shared base)