If you are coming to Go from another language like Ruby or Python there are a lot of changes to take in, and many of these revolve around the string
type. Below is a list of some quick tips that answered questions I had during my first few weeks using Golang.
Creating a multiline string in Go is actually incredibly easy. Simply use the backtick (`
) character when declaring or assigning your string value.
str := `This is a
multiline
string.`
But be careful - any spacing you use in the string to retain indentation will also be present in the final string.
str := `This string
will have
tabs in it`
Go 1.10 has a new strings.Builder
!
While the code below still works, Go 1.10 introduced the Builder type to the strings
package which can be easier to use and is typically a little more efficient. I’ve written about using it in the article, Concatenating and Building Strings in Go 1.10+.
While Go does allow you to concatenate strings with the +
operator, this can become pretty inefficient when concatenating a lot of strings together. It is much more efficient to use a bytes.Buffer
and then convert it to a string once you have concatenated everything.
package main
import (
"bytes"
"fmt"
)
func main() {
var b bytes.Buffer
for i := 0; i < 1000; i++ {
b.WriteString(randString())
}
fmt.Println(b.String())
}
func randString() string {
// Pretend to return a random string
return "abc-123-"
}
You can also use the strings.Join
function if you have all of the strings ahead of time.
package main
import (
"fmt"
"strings"
)
func main() {
var strs []string
for i := 0; i < 1000; i++ {
strs = append(strs, randString())
}
fmt.Println(strings.Join(strs, ""))
}
func randString() string {
// Pretend to return a random string
return "abc-123-"
}
In many languages you can easily convert any data type into a string simply by concatenating it with a string, or by using string interpolation (eg "ID=#{id}"
in ruby). Unfortunately, if you try to do what seems obvious in Go, like casting an int to a string, you are unlikely to get what you expected.
i := 123
s := string(i)
What would you expect the output of s to be? If you guess "123"
like most people would, you would sadly be mistaken. Instead you would get something like "E"
as s
’s value. That isn’t at all what we wanted!
Instead you should look to use packages like strconv or functions like fmt.Sprintf
. For example, here is an example using strconv.Itoa
to convert an integer into a string.
package main
import (
"fmt"
"strconv"
)
func main() {
i := 123
t := strconv.Itoa(i)
fmt.Println(t)
}
You can also use the fmt.Sprintf
function to convert pretty much any data type into a string, but this should generally be reserved for instances where you are actually creating strings with embedded data, not when you want to convert a single integer into a string.
package main
import "fmt"
func main() {
i := 123
t := fmt.Sprintf("We are currently processing ticket number %d.", i)
fmt.Println(t)
}
fmt.Sprintf
operates pretty much identically to fmt.Printf
except instead of printing out the resulting string to standard output it instead returns it as a string.
Limit your Sprintf
usage
As I mentioned before, fmt.Sprintf
should typically be reserved for creating strings with embedded values. There are a few reasons for this, but the most prominent one is that fmt.Sprintf
doesn’t do any type checking, so you are unlikely to catch any bugs until you actually run your code.
fmt.Sprintf
is also slower than most functions you would typically use in the strconv
package, though if I am being honest the speed difference is so minimal it isn’t typically worth considering.
This one isn’t really a “quick tip”, but it is a question I see asked a lot.
How do you create random strings in Go?
Sounds simple enough. Many languages like Ruby and Python provide some helpers that make generating a random string really easy, so surely Go has one, right? Wrong.
Rather than trying to provide all of these utilities, Go instead opts to provide building blocks to developers. As a result, you have a way to generate random data, but turning that into a string is left as an exercise to the developer. While this might be a turn off at first, the upside is that you get to completely dictate how the string is generated. This means you can dictate the character set, how your random generation is seeded, and any other pertinent details. In short, you have more control but at the cost of needing to write a little extra code.
Here is a quick example using the math/rand package and a set of alphanumeric characters as the character set.
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
fmt.Println(RandString(10))
}
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
func RandString(length int) string {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
b := make([]byte, length)
for i := range b {
b[i] = charset[r.Intn(len(charset))]
}
return string(b)
}
The Go Playground always outputs the same string
If you run this code several times on the Go Playground you might notice that it always outputs the same string - 2sdGzJ6rKk
.
This happens because the Go Playground always uses the same time, so when we created our source with the rand.NewSource
function and passed in the current time that value is always the same, so our generated strings will always be the same. If we were to run this on our own computer, the results would vary with every run.
There are likely more optimal solutions than this one for your particular needs, but it is a good starting point. If you are looking for ways to improve/change the code, you might consider using the crypto/rand
package for generating random data - this is generally safer, but can end up being more work.
Regardless of what you end up using, this example should help get you started. It works well enough for most practical use cases that don’t involve sensitive data like passwords and authentication systems. Just be sure to remember to seed your random number generator! This can be done in the math/rand
package via the rand.Seed
function, or by creating a Source
. I opted to create a source in the example above.
strings
package, HasPrefix
, and custom codeWhen dealing with strings it is incredibly common to want to figure out if a string starts with or ends with a specific string. For example, if your API keys all start with sk_
you might want to verify that all API keys provided in an API request start with this prefix, otherwise doing a database lookup is a massive waste of time.
For functions that sounds like very common use cases, your best bet is often to head on over to the strings package and check for something that might help you out. In this case you would want to use the functions strings.HasPrefix(str, prefix) and strings.HasSuffix(str, prefix). You can see them in action below.
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.HasPrefix("something", "some"))
fmt.Println(strings.HasSuffix("something", "thing"))
}
While there are a lot of useful common functions in the strings package, it is worth noting that it isn’t always worth digging around hunting for a package that does what you need. If you are picking up Go after having experience with another language, one common mistake I see is developers spending too much time looking for packages that provide the functionality that they need when they could have easily just written the code themselves.
There are definitely perks to using a standard library; Eg they are tested thoroughly and are well documented. Despite those perks, if you find yourself spending more than a few minute looking for a function it is often just as beneficial to write it yourself. In that case it will be customized for your needs, will be done quickly, and you will completely understand what is happening and won’t be caught off guard by weird edge cases. You also don’t have to worry about someone else maintaining the code.
The comments on reddit pointed out that the correlation between a string and byte slices isn’t always obvious, so while this article originally started out with 5 tips it has been expanded to 6.
In Go you can convert a string into a byte slice ([]byte
) and a byte slice into a string. Doing this is very easy and looks like any other type conversion. This conversion is often performed in order to pass a string into a function that accepts a byte slice, or to pass a byte slice into a function that expects a string.
Below is an example of the conversions:
package main
import "fmt"
func main() {
var s string = "this is a string"
fmt.Println(s)
var b []byte
b = []byte(s)
fmt.Println(b)
for i := range b {
fmt.Println(string(b[i]))
}
s = string(b)
fmt.Println(s)
}
And that’s it for tips on using strings in Go. I hope you found these helpful and informative, and be sure to check out some of my courses like Gophercises (info below) if you want to practice your Go a bit more.
Want to improve your Go skills?
Are you looking to practice Go, but can’t think of a good project to work on? Or maybe you just don’t know what techniques and skills you need to learn next, so you don't know where to start. If so, don’t worry - I’ve got you covered!
Gophercises is a FREE course where we work on exercise problems that are each designed to teach you a different aspect of Go. This includes topics ranging from basic string manipulation all the way to more advanced topics like functional options and concurrency. Each exercise has a sample solution, as well as a screencast (video) where I code the solution while walking you through the code. Plus, the Gophers are really cute 😉
Go is an awesome language whether you are new to programming or have experience in other languages, but learning a new language can be a struggle without the right resources.
To help save you time and get you off to a great start, I have created a guide to learning Go that you can get for FREE! Just sign up for my mailing list (down there ↓over there →) and I'll send it to your inbox.
You will also receive notifications when I release new articles and courses that I think will help you out while learning Go.
Jon Calhoun is a full stack web developer who teaches about Go, web development, algorithms, and anything programming. If you haven't already, you should totally check out his Go courses.
Previously, Jon worked at several statups including co-founding EasyPost, a shipping API used by several fortune 500 companies. Prior to that Jon worked at Google, competed at world finals in programming competitions, and has been programming since he was a child.
Related articles
Spread the word
Did you find this page helpful? Let others know about it!
Sharing helps me continue to create both free and premium Go resources.
Want to discuss the article?
See something that is wrong, think this article could be improved, or just want to say thanks? I'd love to hear what you have to say!
You can reach me via email or via twitter.
©2018 Jonathan Calhoun. All rights reserved.