Byte Me.

What is string in Go?

Cover Image for What is string in Go?
Tan Guven
Tan Guven
- 6 days ago

In Go (Golang), a string is a sequence of Unicode characters and serves as a built-in data type for representing text.

Strings in Go are immutable, meaning that once a string is created, its contents cannot be changed directly.

Although you can manipulate strings using various functions, these operations always produce new strings rather than modifying the original ones.

Internally, a string is a read-only slice of bytes, and it is stored as two components:

  • a pointer to underlying data
  • and its length\

Essential Properties of Strings in Go


Immutable Nature

Strings in Go are immutable, which means that once a string is created, it cannot be changed. Any attempt to modify a string results in the creation of a completely new string.

Default UTF-8 Encoding

By default, strings in Go are stored using UTF-8 encoding, which allows them to handle Unicode characters seamlessly.

Byte-Based Length

The length of a string in Go is calculated based on the total number of bytes it contains, rather than the count of individual characters (runes). This is because a single character can be represented by multiple bytes in UTF-8 encoding.

Strings in Golang

String Declaration


You can declare strings in Go using double quotes ("") for plain strings or backticks (`) for raw strings.

import "fmt"

func main() {
   plainString := "Hello world!"
   fmt.Println(plainString) // Hello world!

   // Raw string supports multiline and includes 
   // escape characters
   rawStr := `This is a raw
string "literal" with\n a new line
   `
   fmt.Println(rawStr)// This is a raw string "literal" with
     // a new line
}

Common String operations


Length of a string


import "fmt"

func main() {
   str := "Hello world!"
   fmt.Println(len(str)) // 12

   rawStr := `This is a rawString "literal" with 
a new line
   `
   fmt.Printf("%s", rawStr) 
   // This is a rawString "literal" with 
   // a new line
}

Rune in Golang

Accessing runes

A rune is an alias for int32 amd is used to represent individual characters. A rune can be made up of 1 to 3 int32 values. This allows for both single and multibyte characters. String can be accessed like a slice to get individual bytes.

import "fmt"

func main() {
   r := 'A'
   fmt.Printf("%v (%T) %s", r, r, string(r)) 
   //        65 (int32) A

   S := `hello`
   fmt.Printf("%v (%T) %s", S[1], S[1], string(S[1]))
   //        101 (uint8) e
}

String Concatenation

Use the + operator to concatenate strings

import "fmt"

func main() {
   str := "adios, arrivederci"
   strRest := "bye bye, sayonara"

   fmt.Println(str + ", " + strRest) 
   // adios, arrivederci, bye bye, sayonara

   mergedStr := fmt.Sprintf("%s, %s", str, strRest)

   fmt.Println(mergedStr) 
   // adios, arrivederci, bye bye, sayonara
}

Substrings

Use slicing to extract substrings for simple strings that don't contain special symbols. This approach slices the bytes, not the runes.

import "fmt"

func main() {
   start := 0
   end := 5
   str := "Hello world!"

   fmt.Println(str[start:end])

   // in case of Unicode occurrences
   str2 := "not ASCII δΈ–η•ŒπŸ˜Άβ€πŸŒ«οΈγ“γ‚“γ«γ‘γ―δΈ–η•Œ"
   runes := []rune(str2)

   fmt.Println(string(runes[start:])) // SCII δΈ–η•ŒπŸ˜Άβ€πŸŒ«οΈγ“γ‚“γ«γ‘γ―δΈ–η•Œ
}

Iterating over a string

Use for to iterate over bytes

import "fmt"

func main() {
   str := "Hello γ“γ‚“γ«γ‘γ―δΈ–η•Œ"

   // In Go, range over a string iterates over Unicode code points (runes), not bytes.
   for _, c := range str {
      fmt.Printf("%c", string(c)) // Hello γ“γ‚“γ«γ‘γ―δΈ–η•Œ
   }

   // str[i] will give you the byte at index i, which means this loop is iterating over 
   // each byte of the string individually.
   for i := 0; i < len(str); i++ {
      fmt.Printf("%c", str[i]) // Hello γ“γ‚“γ«γ‘γ―δΈ–η•Œ
   }
}

Convert between strings and byte slices

String can be converted to byte slices and vice versa

import "fmt"

func main() {
   str := "Hello γ“γ‚“γ«γ‘γ―δΈ–η•Œ"

   b := []byte(str) // convert to byte slice
   fmt.Println(b)   // [72 101 108 108 111 32 228 184 150 33]

   // Convert byte slice back to string
   newStr := string(b)
   fmt.Println("Converted back to string:", newStr)
}

Performance Considerations

Converting a string to a []byte or []rune has a performance cost. Use it carefully in performance-critical applications. For heavy string manipulations, consider working directly with []byte or []rune to avoid repeated conversions.

String Comparison in Go


In Go, comparing strings is straightforward and efficient. The language provides built-in operators and functions to handle string comparison tasks. Here’s what you need to know:

Comparing Strings with Operators

Go allows you to use the standard comparison operators (==, !=, <, <=, >, >=) for strings. These comparisons are lexicographical, meaning they compare the strings byte by byte in Unicode code point order.

import "fmt"

func main() {
    str1 := "apple"
    str2 := "banana"

    fmt.Println(str1 == str2) // false
    fmt.Println(str1 != str2) // true
    fmt.Println(str1 < str2)  // true (lexicographical order)
    fmt.Println(str1 > str2)  // false

    str1 = "Hello"
    str2 = "hello"

    // Case-sensitive comparison
    fmt.Println(str1 == str2) // false

    // Case-insensitive comparison
    fmt.Println(strings.EqualFold(str1, str2)) // true
}

Sorting Strings


Since Go compares strings lexicographically, you can use these operators to sort strings.

import (
    "fmt"
    "sort"
)

func main() {
    fruits := []string{"banana", "apple", "cherry"}
    sort.Strings(fruits)
    fmt.Println(fruits) // [apple banana cherry]
}

String comparison in Go is simple yet powerful. Whether you need to check equality, sort data, or validate user input, Go provides the tools to handle it efficiently and effectively. Just remember: Go compares strings byte by byte, so consider using case-insensitive methods when needed!


Conclusion

Strings in Go are a versatile and essential aspect of the language, providing robust features for text handling. Their immutable nature, UTF-8 encoding, and powerful built-in functions make strings both simple to use and efficient. Whether you are manipulating, comparing, or iterating over strings, Go equips you with the necessary tools to handle them effectively.

As you delve into more complex applications, remember that performance is crucial. Pay attention to conversions between strings, bytes, and runes, especially in performance-critical scenarios. With this foundational understanding, you’re equipped to utilize Go’s string capabilities like a professional!

As always, take care in that coding journey, and I’ll catch you next time! 🀘


Sources