From 23b25248e6adc0b51d37f233e85df3ab2b6c7cfd Mon Sep 17 00:00:00 2001 From: Domenico Corvasce Date: Wed, 22 Jan 2025 13:43:20 +0100 Subject: [PATCH] Add strings.Builder example in for's benchmark section (#838) * Add notes about using and benchmarking strings.Builder * Add new version of for example * Update roman numerals tutorial with backlink * Fix phrasing --- for/v3/repeat.go | 14 ++++++++++++++ for/v3/repeat_test.go | 12 ++++++++++++ iteration.md | 37 +++++++++++++++++++++++++++++++++++++ roman-numerals.md | 3 ++- 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 for/v3/repeat.go create mode 100644 for/v3/repeat_test.go diff --git a/for/v3/repeat.go b/for/v3/repeat.go new file mode 100644 index 000000000..08656e4f6 --- /dev/null +++ b/for/v3/repeat.go @@ -0,0 +1,14 @@ +package iteration + +import "strings" + +const repeatCount = 5 + +// Repeat returns character repeated 5 times. +func Repeat(character string) string { + var repeated strings.Builder + for i := 0; i < repeatCount; i++ { + repeated.WriteString(character) + } + return repeated.String() +} diff --git a/for/v3/repeat_test.go b/for/v3/repeat_test.go new file mode 100644 index 000000000..fd7d5e69c --- /dev/null +++ b/for/v3/repeat_test.go @@ -0,0 +1,12 @@ +package iteration + +import "testing" + +func TestRepeat(t *testing.T) { + repeated := Repeat("a") + expected := "aaaaa" + + if repeated != expected { + t.Errorf("expected %q but got %q", expected, repeated) + } +} diff --git a/iteration.md b/iteration.md index c2dc8b7aa..044cb8266 100644 --- a/iteration.md +++ b/iteration.md @@ -127,6 +127,41 @@ What `136 ns/op` means is our function takes on average 136 nanoseconds to run \ **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)**. +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. + +The standard library provides the `strings.Builder`[stringsBuilder] type which minimizes memory copying. +It implements a `WriteString` method which we can use to concatenate strings: + +```go +const repeatCount = 5 + +func Repeat(character string) string { + var repeated strings.Builder + for i := 0; i < repeatCount; i++ { + repeated.WriteString(character) + } + return repeated.String() +} +``` + +**Note**: We have to call the `String` method to retrieve the final result. + +We can use `BenchmarkRepeat` to confirm that `strings.Builder` significantly improves performance. +Run `go test -bench=. -benchmem`: + +```text +goos: darwin +goarch: amd64 +pkg: github.com/quii/learn-go-with-tests/for/v4 +10000000 25.70 ns/op 8 B/op 1 allocs/op +PASS +``` + +The `-benchmem` flag reports information about memory allocations: + +* `B/op`: the number of bytes allocated per iteration +* `allocs/op`: the number of memory allocations per iteration + ## Practice exercises * 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 \ * More TDD practice * Learned `for` * Learned how to write benchmarks + +[stringsBuilder]: https://pkg.go.dev/strings#Builder diff --git a/roman-numerals.md b/roman-numerals.md index bf8912bab..e82a9f1ed 100644 --- a/roman-numerals.md +++ b/roman-numerals.md @@ -208,7 +208,8 @@ func ConvertToRoman(arabic int) string { } ``` -You may not have used [`strings.Builder`](https://golang.org/pkg/strings/#Builder) before +You might remember [`strings.Builder`](https://golang.org/pkg/strings/#Builder) from our discussion +about [benchmarking](iteration.md#benchmarking) > A Builder is used to efficiently build a string using Write methods. It minimizes memory copying.