Go Strings

Learn string manipulation, handling, and optimization techniques to enhance your coding skills. Elevate your Go programming expertise today.
E
Edtoks10:22 min read

1. What is a String?

In Go, a string is a sequence of characters. It is a fundamental data type, and strings in Go are immutable, meaning their values cannot be changed after they are created. Strings are widely used for representing textual data.

2. Creating a String

In Go, strings can be created using double quotes (") to define a literal string:

package main

import "fmt"

func main() {
    // Creating a string
    str := "Hello, Go Strings!"
    fmt.Println(str)
}

In this example, a string variable str is created and assigned the value "Hello, Go Strings!"

3. String Length

The length of a string in Go can be obtained using the len function:

package main

import "fmt"

func main() {
    // String length
    str := "Hello, Go Strings!"
    length := len(str)
    fmt.Println("Length of the string:", length)
}

The len function returns the number of characters in the string.

4. Accessing Individual Characters of a String

Individual characters in a string can be accessed by their index:

package main

import "fmt"

func main() {
    // Accessing individual characters
    str := "Go Language"
    for i := 0; i < len(str); i++  {
        fmt.Printf("%x ", str[i])
    }
}

Go uses zero-based indexing, so str[0] accesses the first character, and so on.

5. Accessing Individual Bytes of a String

In Go, strings are made up of bytes, and you can access individual bytes using the same indexing approach:

package main

import "fmt"

func main() {
    // Accessing individual characters
    str := "Go Language"
    for i := 0; i < len(str); i++  {
        fmt.Printf("%x ", str[i])
    }
}

This is same as accessing character with index. This is to show each character in a string is stored as a byte in Go. Here %x is the format specifier for hexadecimal.

6. Creating a String from a Slice of Bytes

If you have a slice of bytes, you can create a string from it using type conversion:

package main

import "fmt"

func main() {
    // Creating a string from a slice of bytes
    byteSlice := []byte{71, 111}
    str := string(byteSlice)
    fmt.Println("String from bytes:", str)
}

This example creates a slice of bytes and converts it to a string using the string function.

7. Strings are Immutable

In Go, strings are immutable, meaning their values cannot be changed after creation. Attempts to modify a string will result in a new string being created:

package main

import "fmt"

func main() {
    // Strings are immutable
    str := "Go"
    // This will create a new string, not modify the existing one
    modifiedStr := str + "lang"
    fmt.Println("Original string:", str)
    fmt.Println("Modified string:", modifiedStr)
}

Here, the concatenation operation creates a new string rather than modifying the original.

8. String Rune

In Go, a rune is an alias for int32 and represents a Unicode code point. Go uses runes to represent individual characters in a string. Understanding runes is crucial when dealing with Unicode characters, as strings in Go are UTF-8 encoded. Here are three examples illustrating the use of runes in Go strings:

Example 1: Iterating Over Runes in a String

package main

import "fmt"

func main() {
    str := "Go言語" // "Go言語" means "Go language" in Japanese

    // Iterate over runes in the string
    for _, r := range str {
        fmt.Printf("%c ", r)
    }
    fmt.Println()
}

In this example, the string str contains Unicode characters, including Japanese characters. The for loop iterates over each rune in the string, and %c in Printf is used to print the characters. This is a crucial aspect when working with strings containing multi-byte characters.

Example 2: Accessing Individual Runes by Index

package main

import "fmt"

func main() {
    str := "Hello, 世界" // "Hello, 世界" means "Hello, World" in Japanese

    // Accessing individual runes by index
    firstRune := str[0]
    secondRune := str[7]

    fmt.Printf("First Rune: %c\n", firstRune)
    fmt.Printf("Second Rune: %c\n", secondRune)
}

In this example, the string str contains a mix of English and Japanese characters. Individual runes are accessed by their index, demonstrating that even though the string is UTF-8 encoded, you can still access runes using standard indexing.

Example 3: Rune Length and String Length

package main

import "fmt"

func main() {
    str := "Go言語" // "Go言語" means "Go language" in Japanese

    // Rune length
    runeLength := len([]rune(str))

    // String length
    strLength := len(str)

    fmt.Printf("Rune Length: %d\n", runeLength)
    fmt.Printf("String Length: %d\n", strLength)
}

In this example, the string str contains Japanese characters. The len function is used to get the length of the string in bytes and the length of the string in runes. The length in runes is important when dealing with multi-byte characters as it gives the actual number of characters.

Example 4: Rune Conversion and Printing

package main

import "fmt"

func main() {
    // Convert rune to string and print
    runeValue := 'A'
    strFromRune := string(runeValue)
    fmt.Println("String from Rune:", strFromRune)
}

In this example, a single rune ('A') is converted to a string using the string conversion. This is useful when you need to work with runes individually as strings.

Understanding runes is essential for proper handling of Unicode characters in Go strings, especially when dealing with non-ASCII characters or multi-byte encodings. Runes provide a way to represent and manipulate individual characters, ensuring accurate and efficient string processing.

9. String Comparison

String comparison in Go is performed using the == operator. However, when dealing with strings, it's essential to understand the intricacies of comparing Unicode characters, as Go strings are UTF-8 encoded. Here are three examples illustrating different aspects of string comparison:

Example 1: Basic String Comparison

package main

import "fmt"

func main() {
    str1 := "hello"
    str2 := "hello"

    if str1 == str2 {
        fmt.Println("Strings are equal")
    } else {
        fmt.Println("Strings are not equal")
    }
}

In this example, two simple strings, str1 and str2, are compared using the == operator. Since the contents of both strings are the same, the output will be "Strings are equal."

Example 2: Unicode Characters and String Comparison

package main

import "fmt"

func main() {
    str1 := "café"
    str2 := "cafe\u0301" // Using combining acute accent

    if str1 == str2 {
        fmt.Println("Strings are equal")
    } else {
        fmt.Println("Strings are not equal")
    }
}

In this example, str1 and str2 represent the word "café," but the acute accent in str2 is represented using a combining character (\u0301). Despite the visual similarity, the two strings are not considered equal when compared using ==. Unicode normalization may be necessary for accurate comparisons in such cases.

Here highlighted the importance of understanding Unicode characters in string comparison. The combining accent in one string makes them visually similar but not equal.

Example 3: Case-Insensitive String Comparison

package main

import "strings"

func main() {
    str1 := "Hello"
    str2 := "hello"

    if strings.EqualFold(str1, str2) {
        fmt.Println("Strings are equal (case-insensitive)")
    } else {
        fmt.Println("Strings are not equal (case-insensitive)")
    }
}

In this example, the strings.EqualFold function is used for case-insensitive string comparison. Unlike the == operator, EqualFold considers strings with different cases as equal. This is useful when you need to perform case-insensitive comparisons.

Example 4: Comparison with cmp Package

package main

import "github.com/google/go-cmp/cmp"

type Person struct {
    Name string
    Age  int
}

func main() {
    person1 := Person{Name: "Alice", Age: 30}
    person2 := Person{Name: "Alice", Age: 30}

    if cmp.Equal(person1, person2) {
        fmt.Println("Persons are equal")
    } else {
        fmt.Println("Persons are not equal")
    }
}

In this example, the cmp package is used for structural equality comparison. The cmp.Equal function compares the fields of the Person structs and determines if they are equal. This approach is helpful when dealing with complex data structures.

Other comparison operators

In Go, you can use the <, <=, >, and >= operators for lexicographic (dictionary) comparison of strings. These operators compare strings based on their Unicode code points. Here are examples illustrating each of these comparison operators:

Example 1: < (Less Than) Operator

package main

import "fmt"

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

    if str1 < str2 {
        fmt.Println("str1 is less than str2")
    } else {
        fmt.Println("str1 is not less than str2")
    }
}

In this example, the < operator compares the strings lexicographically. The output will be "str1 is less than str2" because "apple" comes before "banana" in lexicographic order.

Example 2: <= (Less Than or Equal To) Operator

package main

import "fmt"

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

    if str1 <= str2 {
        fmt.Println("str1 is less than or equal to str2")
    } else {
        fmt.Println("str1 is not less than or equal to str2")
    }
}

In this example, the <= operator checks if str1 is less than or equal to str2. Since the strings are equal, the output will be "str1 is less than or equal to str2."

Example 3: > (Greater Than) Operator

package main

import "fmt"

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

    if str1 > str2 {
        fmt.Println("str1 is greater than str2")
    } else {
        fmt.Println("str1 is not greater than str2")
    }
}

In this example, the > operator checks if str1 is greater than str2. The output will be "str1 is greater than str2" because "banana" comes after "apple" in lexicographic order.

Example 4: >= (Greater Than or Equal To) Operator

package main

import "fmt"

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

    if str1 >= str2 {
        fmt.Println("str1 is greater than or equal to str2")
    } else {
        fmt.Println("str1 is not greater than or equal to str2")
    }
}

In this example, the >= operator checks if str1 is greater than or equal to str2. Since the strings are equal, the output will be "str1 is greater than or equal to str2."

These examples demonstrate how to use the lexicographic comparison operators in Go for different relationships between strings. Remember that these operators compare strings based on their Unicode code points, and the results may differ from what you might expect in a case-sensitive comparison.

10. String Concatenation

String concatenation in Go is done using the + operator:

package main

import "fmt"

func main() {
    // String concatenation
    str1 := "Hello"
    str2 := " World!"
    result := str1 + str2
    fmt.Println(result)
}

The + operator concatenates str1 and str2.

Let's keep in touch!

Subscribe to keep up with latest updates. We promise not to spam you.