📘 Chapter 1 – Go Fundamentals and Tooling
(Python → Go Transition Guide)
1. Why Go? Understanding the Philosophy First
Before writing code, it’s important to understand why Go exists.
Go was created at Google by engineers including Robert Griesemer, Rob Pike, and Ken Thompson.
It was designed to solve problems like:
- Slow compilation times
- Complex dependency management
- Over-engineered abstraction layers
- Hard-to-reason-about concurrency
Core Design Principles of Go
- Simplicity over cleverness
- Explicit over implicit
- Composition over inheritance
- Concurrency as a first-class citizen
- Fast compilation
If you come from Python, you may notice:
| Python | Go |
|---|---|
| Dynamic typing | Static typing |
| Exceptions | Explicit error returns |
| OOP-heavy | Composition-driven |
| Flexible syntax | Strict formatting |
| Runtime magic | Compile-time safety |
Go removes “magic” and replaces it with clarity.
2. Installing and Understanding the Go Toolchain
Installation
Install from the official site: 👉 https://go.dev
Verify installation:
go version
You should see something like:
go version go1.22.x darwin/amd64
Understanding the Go Toolchain
Go is opinionated. Everything revolves around the go command.
Common commands:
go run main.go
go build
go test
go fmt
go mod init
go mod tidy
Key idea: You do not manually manage compilation steps. The toolchain does it.
This is unlike Python, where execution is interpreter-based.
3. Modules & Project Structure
Initialize a new project:
mkdir hello-go
cd hello-go
go mod init github.com/yourname/hello-go
This creates:
go.mod
The go.mod file tracks dependencies.
Example:
module github.com/yourname/hello-go
go 1.22
In Go:
- Dependencies are versioned
- Builds are reproducible
- No virtualenv required
4. Your First Go Program
Create main.go:
package main
import "fmt"
func main() {
fmt.Println("Hello, Go!")
}
Run it:
go run main.go
Breaking This Down
package main
Every Go file belongs to a package.
import "fmt"
Imports are explicit and unused imports cause compilation failure.
func main()
The entry point of executable programs.
5. Variables and Types
Unlike Python:
x = 10
In Go:
var x int = 10
Or shorter:
x := 10
Type Inference
Go infers types but keeps them static.
name := "Aditya" // string
age := 30 // int
You cannot later do:
age = "thirty" // Compile-time error
This is intentional. It prevents runtime surprises.
6. Basic Data Types
Integers
int
int8, int16, int32, int64
uint
Floating Point
float32
float64
Boolean
bool
String
string
Go strings are immutable, like Python.
7. Zero Values (Very Important)
In Go, variables always have a default value.
| Type | Zero Value |
|---|---|
| int | 0 |
| float | 0.0 |
| bool | false |
| string | ”” |
| pointer | nil |
This eliminates uninitialized variable bugs common in C-like languages.
8. Control Structures
If Statement
if x > 10 {
fmt.Println("Greater than 10")
}
No parentheses required. Braces are mandatory.
If with Initialization
if y := compute(); y > 10 {
fmt.Println(y)
}
Scoped initialization inside condition — very common in Go.
For Loop (Only Loop in Go)
Go has only one loop construct: for.
Traditional:
for i := 0; i < 5; i++ {
fmt.Println(i)
}
While-style:
i := 0
for i < 5 {
i++
}
Infinite:
for {
// loop forever
}
No while keyword exists.
9. Switch Statements
switch day {
case "Monday":
fmt.Println("Start of week")
case "Friday":
fmt.Println("Almost weekend")
default:
fmt.Println("Another day")
}
Go switches:
- Do NOT fall through by default
- Can switch without a variable
Example:
switch {
case x > 10:
fmt.Println("Large")
case x > 5:
fmt.Println("Medium")
}
10. Functions
Basic function:
func add(a int, b int) int {
return a + b
}
Shorter parameter syntax:
func add(a, b int) int {
return a + b
}
Multiple Return Values (Very Important)
func divide(a, b int) (int, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
This replaces Python-style exceptions.
Calling it:
result, err := divide(10, 2)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(result)
Explicit error handling is core to Go.
11. Understanding Explicit Error Handling
Python:
try:
...
except:
...
Go:
if err != nil {
return err
}
This is deliberate.
It makes failure paths visible and reviewable.
As a mentor, reinforce:
- Never ignore errors
- Handle or propagate them
12. Formatting & Code Discipline
Go enforces formatting:
go fmt ./...
Unlike Python (PEP8 optional), Go formatting is automatic and universal.
This reduces code review noise and team conflict.
13. Writing Your First Test
Create:
main_test.go
Example:
package main
import "testing"
func TestAdd(t *testing.T) {
result := add(2, 3)
if result != 5 {
t.Errorf("Expected 5, got %d", result)
}
}
Run:
go test
Go’s testing is built-in. No external framework required.
14. Table-Driven Tests (Idiomatic Go)
func TestAdd(t *testing.T) {
tests := []struct {
a, b int
expected int
}{
{2, 3, 5},
{0, 5, 5},
{-1, 1, 0},
}
for _, tt := range tests {
result := add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Expected %d, got %d", tt.expected, result)
}
}
}
This pattern is extremely common in production Go.
15. Key Mindset Shifts for Python Developers
- Less magic, more clarity
- No inheritance hierarchies
- Errors are values
- Formatting is mandatory
- Simple > clever
If something feels “too simple”, that is usually the right approach in Go.
End of Chapter 1
By the End of This Chapter, You Should:
- Install and use Go confidently
- Understand Go syntax basics
- Write simple programs
- Handle errors properly
- Write basic tests
- Use the Go toolchain comfortably