Strings in Golang

Strings are one of the most used data structures in almost all languages, and Golang is no exception either. Strings in the Go language are a series of bytes that usually represent text characters. The bytes in the strings can be represented in the Unicode Text using the UTF-8 encoding, because of which we can define any language using Go strings.

We are going to look at the below things in this post

Let’s look at them one by one.

How to create strings in the Go language?

We majorly use the below techniques to create the strings in the Go language –

Let’s look at the above techniques one by one.

Using double quotes ( “” )

Here, the string is created using the double quotes ( ” ) and placing the string in between those double quotes. They can also be called string literals. This kind of string creation cannot span multiple lines, and it is difficult to include the newline character or the tab character, and many more that contain backlash. But we can represent them by using the escape sequences: a backlash followed by characters representing another character.

We can easily create the string in one line using the shorthand declaration.

package main

import (
	"fmt"
)

func main() {

	str1 := "hello codekru"
	fmt.Println("Printing first string:", str1)

	// string with tab character
	str2 := "hello \tcodekru"
	fmt.Println("Printing second string:", str2)

	// string using backlash to have the tab character in the string
	str3 := "hello \\t codekru"
	fmt.Println("Printing third string:", str3)
}

Output –

Printing first string: hello codekru
Printing second string: hello   codekru
Printing third string: hello \t codekru
Using backtick

Here, the string is created using the backticks, also called the “raw literals“. It can contain any character within the string except the backtick. These kinds of strings do not support escape characters and can span between multiple lines.

package main

import (
	"fmt"
)

func main() {

	str1 := `hello codekru`
	fmt.Println("Printing first string:", str1)

	// string with tab character
	str2 := `hello \tcodekru`
	fmt.Println("Printing second string:", str2)

	// string spanning between multiple lines
	str3 := `hello 
			 codekru`
	fmt.Println("Printing third string:", str3)
}

Output –

Printing first string: hello codekru
Printing second string: hello \tcodekru
Printing third string: hello
                         codekru
Creating string from a slice of bytes

We can also create a string from a slice of bytes. We will use the decimal values, but we can also use the hex bytes.

package main

import "fmt"

func main() {

	strSlice := []byte{99, 111, 100, 101, 107, 114, 117}

	str := string(strSlice)

	fmt.Println("String is:", str)

}

Output –

String is: codekru
Creating string from a slice of runes

Similarly, we can create strings from a slice of runes, as illustrated by the program below.

package main

import "fmt"

func main() {

	// slice of runes
	strSlice := []rune{0x63, 0x6f, 0x64, 0x65, 0x6b, 0x72, 0x75}

	str := string(strSlice)

	fmt.Println("String is:", str)

}

Output –

String is: codekru

Iterating over the string

Iterating over the string byte by byte

We can easily iterate over the string byte by byte using the for loop and print the byte values using the %x format specifier.

package main

import "fmt"

func main() {

	str := "codekru"

	fmt.Print("Bytes in the string: ")

	for i := 0; i < len(str); i++ {
		fmt.Printf("%x ", str[i])
	}

}

Output –

Bytes in the string: 63 6f 64 65 6b 72 75 

So, what happened here?

  • First, we found the length of the string using the len() function.
  • Then, we iterated over the string by accessing one byte at a time.
  • And finally, we printed the byte using the %x format specifier and Printf() function of the fmt package.
Printing the characters of a string one by one

It is similar to what we did for the byte, but instead of using the %x format specifier, we will use the %c format specifier.

package main

import "fmt"

func main() {

	str := "codekru"

	fmt.Print("Characters in the string: ")

	for i := 0; i < len(str); i++ {
		fmt.Printf("%c ", str[i])
	}

}

Output –

Characters in the string: c o d e k r u 

An issue with iterating over the string byte by byte

Now, there can be characters in different languages that can acquire more than one byte, and then printing the chars while iterating over the string might not give the exact string we started with.

We will use “Nnọọ” as our string.

package main

import "fmt"

func main() {

	str := "Nnọọ"

	fmt.Print("Bytes in the string: ")

	for i := 0; i < len(str); i++ {
		fmt.Printf("%x ", str[i])
	}
	fmt.Println()

	fmt.Print("Characters in the string: ")

	for i := 0; i < len(str); i++ {
		fmt.Printf("%c", str[i])
	}

}

Output –

Bytes in the string: 4e 6e e1 bb 8d e1 bb 8d 
Characters in the string: Nná»á»

So, what happened here? Why the string printed is not the same as that of the original string?

Here, the character “ọ” takes more than one byte ( e1 bb 8d ); thus, when we try to print these bytes as a character, it results in a different string. And also, please remember here that the len() function returns the number of bytes in the string, which is why we iterated over the string 8 times rather than 4 ( length of the string ).

How to fix this issue?

To fix this issue, we have to use the Rune data type. Rune is an alias for int32 and is mainly used to store the Unicode code points value. For example – The Unicode code point for lowercase a is U+0061 ( decimal value is 97 ). So, let’s try to modify the above program and see whether we can solve this using rune or not.

package main

import "fmt"

func main() {

	str := "Nnọọ"

	runeStr := []rune(str) // using a rune slice here

	fmt.Print("Bytes in the string: ")

	for i := 0; i < len(runeStr); i++ {
		fmt.Printf("%x ", runeStr[i])
	}
	fmt.Println()
	fmt.Print("Characters in the string: ")

	for i := 0; i < len(runeStr); i++ {
		fmt.Printf("%c", runeStr[i])
	}

}

Output –

Bytes in the string: 4e 6e 1ecd 1ecd 
Characters in the string: Nnọọ

So, here, we have solved our problem. We just used a slice of runes and iterated over it to display the characters within the string.

Strings are immutable in Golang

Strings in Golang are immutable, which means they can’t be changed once created. And if we try to change the string, it would throw us an error illustrated by the below program.

package main

import "fmt"

func main() {

	str := "codekru"

	str[0] = 'h'

	fmt.Println("String is:", str)

}

Output –

# command-line-arguments
.codekru.go:9:9: cannot assign to str[0] (strings are immutable)

Zero value of a String

What if we only declare a string variable and do not assign any value to it?

In this case, the string would assume an empty value(“”).

package main

import (
	"fmt"
)

func main() {

	var str string

	fmt.Println("Printing string value:", str)
	fmt.Println("Length of the string:", len(str))

}

Output –

Printing string value: 
Length of the string: 0

We can see that the string assumes an empty value. It can also be verified using the len() function, which would also return 0.

String methods

Below is the list of some of the methods from the strings package of the Go language.

Method name What does it do?
func Contains(s, substr string) bool It tells us whether substr is within s or not.
func Count(s, substr string) int It counts the number of non-overlapping instances of substr in s.
func HasPrefix(s, prefix string) bool  It tells us whether the string s begins with the prefix or not.
func HasSuffix(s, suffix string) bool It tells us whether the string s ends with the suffix or not.
func Index(s, substr string) int It returns the index of the first instance of substr in s.
func Join(elems []string, sep string) string It concatenates the elements of its first argument to create a single string and the separator string sep is placed between elements in the resulting string.
func LastIndex(s, substr string) int It returns the index of the last instance of substr in s.
func Repeat(s string, count int) string It returns a new string consisting of count copies of the string s.
func Replace(s, old, new string, n int) string It returns a copy of the string s with the first n non-overlapping instances of old replaced by new.
func ReplaceAll(s, old, new string) string It returns a copy of the string s with all non-overlapping instances of old replaced by new.
func Trim(s, cutset string) string It returns a slice of the string s with all leading and trailing Unicode code points contained in the cutset removed.
func TrimSpace(s string) string It returns a slice of the string s, with all leading and trailing white space removed, as defined by Unicode.
func ToLower(s string) string It returns s with all Unicode letters mapped to their lower case.
func ToUpper(s string) string It returns s with all Unicode letters mapped to their upper case.

We hope that you have liked our article. If you have any doubts or concerns, please feel free to write us in the comments or mail us at [email protected]

Liked the article? Share this on

Leave a Comment

Your email address will not be published.