Web Analytics

Strings

Beginner ~25 min read

Strings are sequences of characters used to represent text. In this lesson, you'll learn how Go handles strings, understand UTF-8 encoding, work with runes, and master common string operations.

String Basics

In Go, strings are immutable sequences of bytes. They're typically UTF-8 encoded, which means they can represent any Unicode character:

Output
Click Run to execute your code
Key Points:
  • Strings are enclosed in double quotes: "Hello"
  • Raw strings use backticks: `raw string`
  • Strings are immutable - you can't change individual characters
  • UTF-8 encoded by default

String Literals

// Interpreted string (with escape sequences)
s1 := "Hello\nWorld"  // \n is newline

// Raw string (no escape sequences)
s2 := `Hello\nWorld`  // \n is literal text

// Multi-line raw string
s3 := `This is a
multi-line
string`
Pro Tip: Use raw strings (backticks) for:
  • Multi-line strings
  • Regular expressions
  • File paths (especially on Windows)
  • JSON or HTML templates

Common String Operations

The strings package provides many useful functions for working with strings:

Function Description Example
len(s) Length in bytes len("Hello") β†’ 5
strings.ToUpper(s) Convert to uppercase ToUpper("hello") β†’ "HELLO"
strings.ToLower(s) Convert to lowercase ToLower("HELLO") β†’ "hello"
strings.Contains(s, substr) Check if contains substring Contains("Hello", "ell") β†’ true
strings.Replace(s, old, new, n) Replace substring Replace("Hi Hi", "Hi", "Bye", 1) β†’ "Bye Hi"
strings.Split(s, sep) Split into slice Split("a,b,c", ",") β†’ ["a", "b", "c"]
strings.Join(slice, sep) Join slice into string Join(["a", "b"], ",") β†’ "a,b"
strings.TrimSpace(s) Remove leading/trailing whitespace TrimSpace(" hi ") β†’ "hi"

String Concatenation

// Using + operator
greeting := "Hello" + " " + "World"

// Using fmt.Sprintf
name := "Alice"
message := fmt.Sprintf("Hello, %s!", name)

// Using strings.Builder (efficient for loops)
var builder strings.Builder
builder.WriteString("Hello")
builder.WriteString(" ")
builder.WriteString("World")
result := builder.String()
Best Practice: For concatenating many strings in a loop, use strings.Builder instead of +. It's much more efficient!

Runes and UTF-8

Go strings are UTF-8 encoded. A rune represents a single Unicode code point:

Output
Click Run to execute your code
Understanding Bytes vs Runes:
  • byte - A single 8-bit value (alias for uint8)
  • rune - A Unicode code point (alias for int32)
  • len(s) - Returns byte length, not character count
  • Use range to iterate over runes

Why This Matters

s := "Hello, δΈ–η•Œ"
fmt.Println(len(s))           // 13 bytes (not 9 characters!)

// Counting actual characters
count := 0
for range s {
    count++
}
fmt.Println(count)            // 9 characters

// Or use utf8.RuneCountInString
fmt.Println(utf8.RuneCountInString(s))  // 9
Common Pitfall: len() returns the byte length, not the character count. For non-ASCII strings, these can be different!

String Indexing and Slicing

s := "Hello"

// Indexing gives you bytes
fmt.Println(s[0])     // 72 (byte value of 'H')
fmt.Printf("%c\n", s[0])  // H (character)

// Slicing
fmt.Println(s[0:2])   // "He"
fmt.Println(s[2:])    // "llo"
fmt.Println(s[:3])    // "Hel"

// ⚠️ Be careful with multi-byte characters!
s2 := "δΈ–η•Œ"
fmt.Println(s2[0:3])  // "δΈ–" (one character, 3 bytes)

Common Mistakes

1. Trying to modify strings

// ❌ Wrong - strings are immutable
s := "Hello"
s[0] = 'h'  // Error: cannot assign to s[0]

// βœ… Correct - create a new string
s := "Hello"
s = "h" + s[1:]  // "hello"

// Or convert to []rune, modify, convert back
runes := []rune(s)
runes[0] = 'h'
s = string(runes)

2. Confusing byte length with character count

// ❌ Wrong assumption
s := "Hello, δΈ–η•Œ"
if len(s) == 9 {  // False! len(s) is 13
    fmt.Println("9 characters")
}

// βœ… Correct - count runes
import "unicode/utf8"

if utf8.RuneCountInString(s) == 9 {
    fmt.Println("9 characters")  // True!
}

3. Inefficient string concatenation in loops

// ❌ Inefficient - creates many temporary strings
result := ""
for i := 0; i < 1000; i++ {
    result += "x"  // Slow!
}

// βœ… Efficient - use strings.Builder
var builder strings.Builder
for i := 0; i < 1000; i++ {
    builder.WriteString("x")
}
result := builder.String()

Exercise: Word Counter

Task: Create a program that analyzes a sentence.

Requirements:

  • Take a sentence: "Go is simple and powerful"
  • Count the number of words
  • Convert to uppercase
  • Replace "simple" with "elegant"
  • Print all results
Show Solution
package main

import (
    "fmt"
    "strings"
)

func main() {
    sentence := "Go is simple and powerful"
    
    // Original
    fmt.Println("Original:", sentence)
    
    // Word count
    words := strings.Split(sentence, " ")
    fmt.Println("Word count:", len(words))
    
    // Uppercase
    upper := strings.ToUpper(sentence)
    fmt.Println("Uppercase:", upper)
    
    // Replace
    replaced := strings.Replace(sentence, "simple", "elegant", 1)
    fmt.Println("Replaced:", replaced)
    
    // Bonus: Check if contains
    if strings.Contains(sentence, "Go") {
        fmt.Println("Contains 'Go': true")
    }
    
    // Bonus: Character count
    fmt.Println("Character count:", len(sentence))
    fmt.Println("Rune count:", len([]rune(sentence)))
}

Summary

  • Strings are immutable sequences of bytes
  • UTF-8 encoded by default, supporting all Unicode characters
  • Double quotes for interpreted strings, backticks for raw strings
  • rune represents a Unicode code point (int32)
  • len() returns byte length, not character count
  • strings package provides many useful functions
  • Use range to iterate over runes, not bytes
  • strings.Builder for efficient concatenation in loops

What's Next?

Congratulations on completing the Basics module! You now understand variables, types, constants, operators, and strings. Next, you'll learn about Control Flow with if statements and switch expressions to make decisions in your programs.