🧵 Go Strings: The Magic Thread of Text
Imagine you have a magical thread made of tiny beads. Each bead is a letter or symbol. Once you string them together, you can’t change a single bead without making a whole new thread!
🎯 What We’ll Learn
We’re going to explore 5 magical secrets about strings in Go:
- String Type – What is this magic thread?
- String Literals – How do we create strings?
- String Immutability – Why can’t we change them?
- Rune Type – The super-beads for world languages
- Byte Type – The tiny building blocks
📦 1. The String Type
What Is a String?
A string is just a bunch of characters (letters, numbers, symbols) stuck together. Think of it like a necklace of beads where each bead is a character.
name := "Gopher"
Here, name holds 6 characters: G, o, p, h, e, r.
The Secret Inside
In Go, a string is actually two things bundled together:
- A pointer (like an arrow pointing to where the beads are stored)
- A length (how many beads are on the thread)
graph TD A["String Variable"] --> B["Pointer to Data"] A --> C["Length: 6"] B --> D["G o p h e r"]
Quick Example
greeting := "Hello, World!"
fmt.Println(len(greeting))
// Output: 13
The len() function counts bytes, not characters. More on this soon!
✍️ 2. String Literals
Two Ways to Write Strings
Think of it like two ways to wrap a gift:
🎁 Method 1: Double Quotes (Interpreted)
msg := "Hello\nWorld"
The \n is a magic code that means “new line”. Go interprets these codes.
Output:
Hello
World
Common Magic Codes:
| Code | Meaning |
|---|---|
\n |
New line |
\t |
Tab space |
\\ |
Backslash |
\" |
Quote mark |
🎁 Method 2: Backticks (Raw)
path := `C:\Users\Gopher`
With backticks, what you see is what you get. No magic codes! Perfect for:
- File paths on Windows
- Regular expressions
- Multi-line text
poem := `Roses are red,
Violets are blue,
Go is awesome,
And so are you!`
🔒 3. String Immutability
The Golden Rule: Strings Can’t Change!
Once you create a string, you cannot change its characters. It’s like a frozen necklace – you can look at it, but you can’t swap any beads.
name := "Gopher"
// This will NOT work:
// name[0] = 'M' ❌ Error!
But Wait… This Works?
name := "Gopher"
name = "Moopher" // ✅ This is OK!
What’s the trick? 🎩
You’re not changing the old string. You’re making a brand new string and pointing name to it!
graph TD subgraph Before A["name"] --> B["Gopher"] end subgraph After C["name"] --> D["Moopher"] B["Gopher #40;abandoned#41;"] end
Why Immutability is Good
- Safety – No one can secretly change your string
- Sharing – Multiple variables can safely share the same string
- Speed – Go can optimize because it knows strings won’t change
🌍 4. The Rune Type
The Problem with Bytes
English letters fit in 1 byte each. But what about emojis 🎉 or Chinese 中 or Hindi हिंदी?
These need more space!
Enter the Rune: A Super-Bead
A rune in Go represents a single character from any language. It’s like a universal bead that can be any symbol in the world!
var r rune = '中' // Chinese character
fmt.Println(r) // 20013 (its code number)
A rune is actually an int32 (a 32-bit number) which can represent any character in the world using Unicode.
Strings vs Runes
text := "Hello, 世界"
// Length in BYTES
fmt.Println(len(text)) // 13
// Length in CHARACTERS (runes)
fmt.Println(
len([]rune(text))) // 9
Why different? “世界” (meaning “world” in Chinese) uses 6 bytes for just 2 characters!
graph TD A["Hello, 世界"] --> B["7 bytes for 'Hello, '"] A --> C["6 bytes for '世界'"] B --> D["Total: 13 bytes"] C --> D D --> E["But only 9 runes/characters"]
Looping Through Characters
text := "Go语言"
// Loop by RUNE (correct way)
for i, r := range text {
fmt.Printf("%d: %c\n", i, r)
}
// 0: G
// 1: o
// 2: 语
// 5: 言
Notice the index jumps from 2 to 5? That’s because each Chinese character takes 3 bytes!
🧱 5. The Byte Type
The Tiniest Building Block
A byte is the smallest piece of data – just 8 bits (like 8 tiny switches that can be on or off).
In Go, a byte is the same as uint8 (a number from 0 to 255).
var b byte = 'A'
fmt.Println(b) // 65
The letter ‘A’ has the code number 65!
Strings Are Made of Bytes
text := "Go"
fmt.Println(text[0]) // 71 (code for 'G')
fmt.Println(text[1]) // 111 (code for 'o')
When you index a string with [0], you get a byte, not a rune!
Converting to Byte Slice
text := "Hello"
bytes := []byte(text)
fmt.Println(bytes)
// [72 101 108 108 111]
This is useful when you need to:
- Write to files
- Send data over the network
- Modify string contents (by making a copy)
The Byte vs Rune Summary
| Feature | Byte | Rune |
|---|---|---|
| Size | 8 bits (1 byte) | 32 bits (4 bytes) |
| Type | uint8 |
int32 |
| Holds | ASCII characters | Any Unicode character |
| Use | Raw data, English | World languages, emojis |
🎨 The Big Picture
graph TD A["String in Go"] --> B["Immutable Sequence"] B --> C["Made of Bytes"] C --> D["Can represent Runes"] E["String Literals"] --> F["Double Quotes"] E --> G["Backticks Raw"] H["Character Types"] --> I["byte - 8 bit"] H --> J["rune - 32 bit"]
🚀 Quick Recap
| Concept | One-Liner |
|---|---|
| String Type | A read-only slice of bytes with a length |
| String Literals | Use "quotes" for interpreted, `backticks` for raw |
| Immutability | Strings can’t be changed, only replaced |
| Rune | A int32 representing any Unicode character |
| Byte | A uint8 representing raw 8-bit data |
💡 Pro Tips
- Use
rangeto loop over runes in a string - Use
len()for byte count,len([]rune())for character count - Backticks are your friend for file paths and regex
- Never try to modify a string – create a new one instead
Now you know the magic of Go strings! They’re like frozen threads of beads – beautiful, efficient, and impossible to mess up once created. 🧵✨
