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
- How to create the strings in the Go language?
- Iterating over the string
- Strings are immutable
- Zero value of a string
- And some of the string methods
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 –
- Using double quotes ( “” )
- Using backticks
- Creating string from a slice of bytes
- And, Creating string from a slice of runes
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 admin@codekru.com.