DEV Community

Lane Wagner for Qvault

Posted on • Originally published at qvault.io on

Concatenating with strings.Builder Quickly in Golang

knot in string unsplash

The post Concatenating with strings.Builder Quickly in Golang first appeared on Qvault.

The Go standard library makes concatenating strings easy. Concatenation is just a fancy word for adding strings together to make a larger string. For example, if we concatenate "hello", " " and "world" we’d get "hello world".

The built-in fmt.Sprintf function takes a format and a variadic list of interfaces as input.

func Sprintf(format string, a ...interface{}) string
Enter fullscreen mode Exit fullscreen mode

The formatting option lets us template out how the final string will look, then we can add inputs that will be interpolated into the string.

s := fmt.Sprintf("%v has been subscribed since %v.\n", user.Name, user.CreatedAt)
Enter fullscreen mode Exit fullscreen mode

%v is a simple token that will be replaced by the default format of whatever the given arguments are. In our case, it was a string and a time.Time. Check out the documentation for all the formatting options.

Efficient string concatenation

Go 1.10+ released the awesome strings.Builder type, which lets us more efficiently build strings. Because it minimizes memory copying, strings.Builder is a high-performance option when it comes to doing bulk string concatenation.

Quickly writing a user list – example

First, let’s create an empty builder.

var builder strings.Builder
Enter fullscreen mode Exit fullscreen mode

Next, let’s add a title string to our list.

b.WriteString("user list\n")
Enter fullscreen mode Exit fullscreen mode

Now we’ll iterate from 0-9, and for each number write a line containing “user #{i}“. Because strings.Builder implements the io.Writer interface, we can use the standard fmt.Fprintf function.

for i := 0; i < 10; i++ {
    fmt.Fprintf(&b, "user #%d\n", i)
}
Enter fullscreen mode Exit fullscreen mode

To actually print the full string we can use the String() method.

fmt.Println(b.String())
Enter fullscreen mode Exit fullscreen mode

Full code:

package main

import (
    "fmt"
    "strings"
)

func main() {
    var b strings.Builder
    b.WriteString("user list\n")
    for i := 0; i < 10; i++ {
        fmt.Fprintf(&b, "user #%d\n", i)
    }
    fmt.Println(b.String())
}
Enter fullscreen mode Exit fullscreen mode

Preallocation for more speed

If you really want to speed up your string building, and you already know the size of your final string, you can use the builder’s Grow() method to preallocate the size of the buffer. This saves your code from needing to grow the memory dynamically.

// Grow grows b's capacity, if necessary, to guarantee space for another n bytes.
// After Grow(n), at least n bytes can be written to b without another allocation.
// If n is negative, Grow panics.
func (b *Builder) Grow(n int)
Enter fullscreen mode Exit fullscreen mode

So to preallocate for our example we could do the following.

package main

import (
    "fmt"
    "strings"
)

func main() {
    var b strings.Builder
    b.Grow(90) // we will be writing 90 bytes
    b.WriteString("user list\n")
    for i := 0; i < 10; i++ {
        fmt.Fprintf(&b, "user #%d\n", i)
    }
    fmt.Println(b.String())
}
Enter fullscreen mode Exit fullscreen mode

Thanks for reading, now take a course!

Interested in a high-paying job in tech? Land interviews and pass them with flying colors after taking my hands-on coding courses.

Start coding now

Questions?

Follow and hit me up on Twitter @q_vault if you have any questions or comments. If I’ve made a mistake in the article be sure to let me know so I can get it corrected!

Subscribe to my newsletter for more coding articles delivered straight to your inbox.

Discussion (1)

Collapse
altiano profile image
Altiano Gerung • Edited

any benchmarking?