🚀 Getting Started with Go: The Startup Crew
The Big Idea: Meet the Startup Crew
Imagine you’re opening a brand new bakery. Before customers walk in, you need to:
- Turn on the ovens 🔥
- Set up ingredients in the right order 🥚🥛
- Import special tools even if you don’t use them directly 📦
- Throw away packaging you don’t need 🗑️
Go programs work exactly like this! Let’s meet your Startup Crew.
🎬 The init Function: Your Secret Helper
What is it?
The init function is like a silent helper that sets things up before your main show begins. You never call it—Go does it automatically!
Simple Example
package main
import "fmt"
func init() {
fmt.Println("Setting up...")
}
func main() {
fmt.Println("Welcome!")
}
Output:
Setting up...
Welcome!
See? init ran first, even though we never called it!
Key Facts
- âś… Runs automatically before
main() - âś… No arguments, no return values
- âś… You can have multiple
initfunctions in one file - âś… Each package can have its own
init
Multiple init Functions
package main
import "fmt"
func init() {
fmt.Println("First helper!")
}
func init() {
fmt.Println("Second helper!")
}
func main() {
fmt.Println("Main event!")
}
Output:
First helper!
Second helper!
Main event!
They run in the order they appear!
đź“‹ Package Initialization Order: The Line-Up
The Big Picture
When your Go program starts, it follows a strict order:
graph TD A[Import Packages] --> B[Package-Level Variables] B --> C[init Functions] C --> D[main Function]
Think of It Like a Movie Set
- Actors arrive = Import packages
- Props are placed = Variables are set
- Stage crew checks everything =
initruns - Director yells ACTION! =
mainruns
Example: The Full Order
package main
import "fmt"
var message = setup()
func setup() string {
fmt.Println("1. Setting up variable")
return "Hello"
}
func init() {
fmt.Println("2. init is running")
}
func main() {
fmt.Println("3. main is running")
fmt.Println(message)
}
Output:
1. Setting up variable
2. init is running
3. main is running
Hello
Multi-Package Order
If package A imports package B:
- Package B initializes first
- Then package A initializes
- Finally,
mainruns
graph TD A[main imports pkg A] --> B[pkg A imports pkg B] B --> C[pkg B variables] C --> D[pkg B init] D --> E[pkg A variables] E --> F[pkg A init] F --> G[main variables] G --> H[main init] H --> I[main function]
📦 Blank Imports: The Silent Workers
What’s the Problem?
Sometimes you need a package’s init function to run, but you don’t use anything else from it.
Go is strict—it won’t let you import unused packages!
The Solution: Blank Import
Use _ (the blank identifier) as the package name:
import _ "image/png"
This says: “Run this package’s init, but I won’t call any functions.”
Real-World Example
package main
import (
"database/sql"
_ "github.com/lib/pq" // PostgreSQL driver
)
func main() {
db, err := sql.Open("postgres", "...")
// The pq package registered
// itself during its init!
}
The PostgreSQL driver uses init to register itself. We never call pq.Something(), but we need it to run!
Common Uses
| Package | Why Blank Import? |
|---|---|
_ "image/png" |
Registers PNG decoder |
_ "image/jpeg" |
Registers JPEG decoder |
_ "github.com/lib/pq" |
Registers PostgreSQL driver |
_ "net/http/pprof" |
Registers profiling handlers |
🗑️ The Blank Identifier: The Trash Can
What is _?
The underscore _ is Go’s way of saying “I don’t need this value.”
It’s like a trash can—you throw things in, but you never look at them again.
Why Use It?
Sometimes functions return values you don’t need:
package main
import "fmt"
func main() {
// We only want the value, not error
value, _ := getStuff()
fmt.Println(value)
}
func getStuff() (int, error) {
return 42, nil
}
Common Uses
1. Ignoring Return Values
// Only need first value
name, _ := getUserInfo()
// Only need second value
_, age := getUserInfo()
2. Checking Interface Implementation
// Compile-time check
var _ Writer = (*MyType)(nil)
3. For Loop Index
names := []string{"Go", "Rust", "Python"}
// Don't need index, just values
for _, name := range names {
fmt.Println(name)
}
4. Blank Import (as we learned!)
import _ "some/package"
Quick Reference
| Use Case | Code |
|---|---|
| Ignore error | val, _ := fn() |
| Ignore value | _, err := fn() |
| Ignore index | for _, v := range |
| Ignore both | for range slice |
| Blank import | import _ "pkg" |
🎯 Putting It All Together
Here’s a complete example using everything:
package main
import (
"fmt"
_ "image/png" // Blank import
)
// Package variable
var config = loadConfig()
func loadConfig() string {
fmt.Println("1. Loading config")
return "ready"
}
func init() {
fmt.Println("2. First init")
}
func init() {
fmt.Println("3. Second init")
}
func main() {
fmt.Println("4. Main running!")
// Blank identifier
for _, letter := range "Go" {
fmt.Printf("%c ", letter)
}
}
Output:
1. Loading config
2. First init
3. Second init
4. Main running!
G o
đź§ Quick Memory Tips
| Concept | Remember |
|---|---|
init |
Runs before main, auto-called |
| Order | Variables → init → main |
| Blank Import | _ "pkg" = run init only |
| Blank Identifier | _ = throw away |
🎉 You Did It!
You now understand Go’s initialization system:
- âś…
initfunctions run automatically - âś… Packages initialize in dependency order
- âś… Blank imports run side effects
- âś…
_ignores unwanted values
These are the invisible helpers that make Go programs work smoothly. Now go build something amazing! 🚀