Skip to content

Commit 23b2524

Browse files
authored
Add strings.Builder example in for's benchmark section (quii#838)
* Add notes about using and benchmarking strings.Builder * Add new version of for example * Update roman numerals tutorial with backlink * Fix phrasing
1 parent 7c2e292 commit 23b2524

File tree

4 files changed

+65
-1
lines changed

4 files changed

+65
-1
lines changed

for/v3/repeat.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package iteration
2+
3+
import "strings"
4+
5+
const repeatCount = 5
6+
7+
// Repeat returns character repeated 5 times.
8+
func Repeat(character string) string {
9+
var repeated strings.Builder
10+
for i := 0; i < repeatCount; i++ {
11+
repeated.WriteString(character)
12+
}
13+
return repeated.String()
14+
}

for/v3/repeat_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package iteration
2+
3+
import "testing"
4+
5+
func TestRepeat(t *testing.T) {
6+
repeated := Repeat("a")
7+
expected := "aaaaa"
8+
9+
if repeated != expected {
10+
t.Errorf("expected %q but got %q", expected, repeated)
11+
}
12+
}

iteration.md

+37
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,41 @@ What `136 ns/op` means is our function takes on average 136 nanoseconds to run \
127127

128128
**Note:** Sometimes, Go can optimize your benchmarks in a way that makes them inaccurate, such as eliminating the function being benchmarked. Check your benchmarks to see if the values make sense. If they seem overly optimized, you can follow the strategies in this **[blog post](https://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go)**.
129129

130+
Strings in Go are immutable, meaning every concatenation, such as in our `Repeat` function, involves copying memory to accommodate the new string. This impacts performance, particularly during heavy string concatenation.
131+
132+
The standard library provides the `strings.Builder`[stringsBuilder] type which minimizes memory copying.
133+
It implements a `WriteString` method which we can use to concatenate strings:
134+
135+
```go
136+
const repeatCount = 5
137+
138+
func Repeat(character string) string {
139+
var repeated strings.Builder
140+
for i := 0; i < repeatCount; i++ {
141+
repeated.WriteString(character)
142+
}
143+
return repeated.String()
144+
}
145+
```
146+
147+
**Note**: We have to call the `String` method to retrieve the final result.
148+
149+
We can use `BenchmarkRepeat` to confirm that `strings.Builder` significantly improves performance.
150+
Run `go test -bench=. -benchmem`:
151+
152+
```text
153+
goos: darwin
154+
goarch: amd64
155+
pkg: github.com/quii/learn-go-with-tests/for/v4
156+
10000000 25.70 ns/op 8 B/op 1 allocs/op
157+
PASS
158+
```
159+
160+
The `-benchmem` flag reports information about memory allocations:
161+
162+
* `B/op`: the number of bytes allocated per iteration
163+
* `allocs/op`: the number of memory allocations per iteration
164+
130165
## Practice exercises
131166

132167
* Change the test so a caller can specify how many times the character is repeated and then fix the code
@@ -138,3 +173,5 @@ What `136 ns/op` means is our function takes on average 136 nanoseconds to run \
138173
* More TDD practice
139174
* Learned `for`
140175
* Learned how to write benchmarks
176+
177+
[stringsBuilder]: https://pkg.go.dev/strings#Builder

roman-numerals.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,8 @@ func ConvertToRoman(arabic int) string {
208208
}
209209
```
210210

211-
You may not have used [`strings.Builder`](https://golang.org/pkg/strings/#Builder) before
211+
You might remember [`strings.Builder`](https://golang.org/pkg/strings/#Builder) from our discussion
212+
about [benchmarking](iteration.md#benchmarking)
212213

213214
> A Builder is used to efficiently build a string using Write methods. It minimizes memory copying.
214215

0 commit comments

Comments
 (0)