Strings
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:
Click Run to execute your code
- 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`
- 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()
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:
Click Run to execute your code
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
rangeto 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
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.
Enjoying these tutorials?