24-Hour GoLang Learning Progress Tracker
Check off each hour as you complete it to track your progress through this comprehensive Go learning journey.
π Introduction & Prerequisites
Welcome to the most comprehensive 24-hour Go learning guide! This intensive course is designed to take you from complete beginner to building concurrent applications with Go (Golang).
What You'll Learn
- Complete Go development environment setup
- Core Go syntax and programming concepts
- Go's unique approach to object-oriented programming
- Concurrency with goroutines and channels
- Web development and REST API creation
- Modern Go features and best practices
- Building a complete concurrent web server
Prerequisites
- Basic programming knowledge (any language)
- Understanding of basic computer science concepts
- Familiarity with command line/terminal
- Basic understanding of web concepts (helpful but not required)
- A computer with internet connection
Pro Tip: Go is designed for simplicity and efficiency. It combines the ease of programming of an interpreted, dynamically typed language with the efficiency and safety of a statically typed, compiled language.
Learning Strategy
Each 2-hour block includes:
- Theory (30 minutes): Core Go concepts and principles
- Practice (60 minutes): Hands-on coding and building
- Application (30 minutes): Real-world examples and exercises
Why Learn Go?
- Simple & Clean: Minimalist syntax, easy to read and write
- Fast Compilation: Compiles to native machine code quickly
- Concurrent by Design: Built-in support for concurrent programming
- Modern Language: Designed for modern computing environments
- Industry Adoption: Used by Google, Docker, Kubernetes, and many others
- Great Performance: Fast execution with low memory footprint
Hour 1-2: Go Environment Setup & First Programs
Understanding Go
Go (often referred to as Golang) is an open-source programming language developed by Google. It's designed for building simple, reliable, and efficient software.
Installing Go
Method 1: Official Installer (Recommended)
- Visit golang.org/dl/
- Download the installer for your operating system
- Run the installer and follow the instructions
- Verify installation by opening terminal and running
go version
Method 2: Package Managers
# macOS (using Homebrew)
brew install go
# Ubuntu/Debian
sudo apt update
sudo apt install golang-go
# CentOS/RHEL
sudo yum install golang
# Windows (using Chocolatey)
choco install golang
# Arch Linux
sudo pacman -S go
Setting Up Go Workspace
# Check Go installation
go version
# Check Go environment
go env
# Important environment variables
echo $GOROOT # Go installation directory
echo $GOPATH # Go workspace (legacy, still useful)
echo $GOBIN # Go binaries directory
# Modern Go uses modules, but let's set up a workspace
mkdir -p ~/go/{bin,src,pkg}
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
Your First Go Program
Hello World
// hello.go
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
fmt.Println("Welcome to Go programming!")
}
Running Go Programs
# Method 1: Run directly
go run hello.go
# Method 2: Build and run
go build hello.go
./hello # On Unix/Linux/macOS
hello.exe # On Windows
# Method 3: Install and run
go install hello.go
hello # If $GOPATH/bin is in your PATH
Go Program Structure
// Every Go file starts with a package declaration
package main
// Import statements
import (
"fmt"
"math"
"time"
)
// Constants
const Pi = 3.14159
// Variables
var message string = "Hello, Go!"
// Functions
func greet(name string) string {
return "Hello, " + name + "!"
}
// Main function - entry point
func main() {
fmt.Println(message)
fmt.Println(greet("Gopher"))
fmt.Printf("Pi is approximately %.2f\n", Pi)
fmt.Println("Current time:", time.Now())
}
Exercise 1.1: Your First Go Programs
Create the following Go programs:
hello.go - Display "Hello, Go World!" with current date and time
calculator.go - Perform basic math operations and display results
info.go - Display system information using Go's built-in packages
module-test.go - Create a Go module and import an external package
Hour 1-2 Summary
Congratulations! You've successfully:
- β
Installed and configured Go development environment
- β
Created your first Go programs
- β
Learned basic Go program structure
- β
Understood Go modules and dependency management
- β
Used essential Go commands
Hour 3-4: Go Syntax & Data Types
Variables and Constants
Go is statically typed, which means variable types are known at compile time.
package main
import "fmt"
func main() {
// Variable declarations
var name string = "John"
var age int = 30
var height float64 = 5.9
var isStudent bool = true
// Short variable declaration (type inference)
message := "Hello, Go!" // string
count := 42 // int
pi := 3.14159 // float64
active := true // bool
// Multiple variable declaration
var (
firstName string = "Jane"
lastName string = "Doe"
score int = 95
)
// Multiple assignment
x, y := 10, 20
a, b, c := 1, 2, 3
// Zero values (default values)
var defaultString string // ""
var defaultInt int // 0
var defaultFloat float64 // 0.0
var defaultBool bool // false
fmt.Println(name, age, height, isStudent)
fmt.Println(message, count, pi, active)
fmt.Println(firstName, lastName, score)
fmt.Println(x, y, a, b, c)
fmt.Println(defaultString, defaultInt, defaultFloat, defaultBool)
}
Constants
package main
import "fmt"
// Package-level constants
const (
StatusOK = 200
StatusNotFound = 404
StatusError = 500
)
const (
// iota generates successive integer constants
Sunday = iota // 0
Monday // 1
Tuesday // 2
Wednesday // 3
Thursday // 4
Friday // 5
Saturday // 6
)
func main() {
// Local constants
const pi = 3.14159
const greeting = "Hello"
// Typed constants
const maxUsers int = 100
const version string = "1.0.0"
fmt.Println(pi, greeting)
fmt.Println(maxUsers, version)
fmt.Println("Today is day", Tuesday)
fmt.Println("HTTP Status:", StatusOK)
}
Basic Data Types
package main
import "fmt"
func main() {
// Numeric types
var int8Val int8 = 127 // -128 to 127
var int16Val int16 = 32767 // -32768 to 32767
var int32Val int32 = 2147483647 // -2^31 to 2^31-1
var int64Val int64 = 9223372036854775807 // -2^63 to 2^63-1
var uint8Val uint8 = 255 // 0 to 255
var uint16Val uint16 = 65535 // 0 to 65535
var uint32Val uint32 = 4294967295 // 0 to 2^32-1
var uint64Val uint64 = 18446744073709551615 // 0 to 2^64-1
// Platform-dependent types
var intVal int = 42 // int32 or int64 depending on platform
var uintVal uint = 42 // uint32 or uint64 depending on platform
var uintptrVal uintptr // Integer type to hold pointer
// Floating-point types
var float32Val float32 = 3.14
var float64Val float64 = 3.141592653589793
// Complex types
var complex64Val complex64 = 1 + 2i
var complex128Val complex128 = 1 + 2i
// Boolean type
var boolVal bool = true
// String type
var stringVal string = "Hello, Go!"
// Byte and rune (aliases)
var byteVal byte = 'A' // alias for uint8
var runeVal rune = 'δΈ' // alias for int32, represents Unicode code point
fmt.Printf("int8: %d, int16: %d, int32: %d, int64: %d\n",
int8Val, int16Val, int32Val, int64Val)
fmt.Printf("uint8: %d, uint16: %d, uint32: %d, uint64: %d\n",
uint8Val, uint16Val, uint32Val, uint64Val)
fmt.Printf("int: %d, uint: %d\n", intVal, uintVal)
fmt.Printf("float32: %f, float64: %f\n", float32Val, float64Val)
fmt.Printf("complex64: %v, complex128: %v\n", complex64Val, complex128Val)
fmt.Printf("bool: %t, string: %s\n", boolVal, stringVal)
fmt.Printf("byte: %c (%d), rune: %c (%d)\n", byteVal, byteVal, runeVal, runeVal)
}
Type Conversions
package main
import (
"fmt"
"strconv"
)
func main() {
// Numeric conversions
var i int = 42
var f float64 = float64(i) // int to float64
var u uint = uint(f) // float64 to uint
// String conversions
var str string = "123"
num, err := strconv.Atoi(str) // string to int
if err != nil {
fmt.Println("Conversion error:", err)
} else {
fmt.Println("Converted number:", num)
}
// Int to string
numStr := strconv.Itoa(42)
fmt.Println("Number as string:", numStr)
// Float to string
floatStr := strconv.FormatFloat(3.14159, 'f', 2, 64)
fmt.Println("Float as string:", floatStr)
// String to float
floatVal, err := strconv.ParseFloat("3.14159", 64)
if err != nil {
fmt.Println("Float conversion error:", err)
} else {
fmt.Println("Converted float:", floatVal)
}
// Boolean conversions
boolStr := strconv.FormatBool(true)
fmt.Println("Bool as string:", boolStr)
boolVal, err := strconv.ParseBool("true")
if err != nil {
fmt.Println("Bool conversion error:", err)
} else {
fmt.Println("Converted bool:", boolVal)
}
fmt.Printf("Original: %d, Float: %f, Uint: %d\n", i, f, u)
}
Operators
package main
import "fmt"
func main() {
a, b := 10, 3
// Arithmetic operators
fmt.Printf("a + b = %d\n", a+b) // Addition: 13
fmt.Printf("a - b = %d\n", a-b) // Subtraction: 7
fmt.Printf("a * b = %d\n", a*b) // Multiplication: 30
fmt.Printf("a / b = %d\n", a/b) // Division: 3 (integer division)
fmt.Printf("a %% b = %d\n", a%b) // Modulus: 1
// Increment/Decrement
x := 5
x++ // x = x + 1
fmt.Printf("After increment: %d\n", x) // 6
x-- // x = x - 1
fmt.Printf("After decrement: %d\n", x) // 5
// Assignment operators
y := 10
y += 5 // y = y + 5
fmt.Printf("y += 5: %d\n", y) // 15
y -= 3 // y = y - 3
fmt.Printf("y -= 3: %d\n", y) // 12
y *= 2 // y = y * 2
fmt.Printf("y *= 2: %d\n", y) // 24
y /= 4 // y = y / 4
fmt.Printf("y /= 4: %d\n", y) // 6
y %= 4 // y = y % 4
fmt.Printf("y %%= 4: %d\n", y) // 2
// Comparison operators
fmt.Printf("a == b: %t\n", a == b) // false
fmt.Printf("a != b: %t\n", a != b) // true
fmt.Printf("a > b: %t\n", a > b) // true
fmt.Printf("a < b: %t\n", a < b) // false
fmt.Printf("a >= b: %t\n", a >= b) // true
fmt.Printf("a <= b: %t\n", a <= b) // false
// Logical operators
p, q := true, false
fmt.Printf("p && q: %t\n", p && q) // AND: false
fmt.Printf("p || q: %t\n", p || q) // OR: true
fmt.Printf("!p: %t\n", !p) // NOT: false
// Bitwise operators
m, n := 12, 10 // 1100, 1010 in binary
fmt.Printf("m & n: %d\n", m&n) // AND: 8 (1000)
fmt.Printf("m | n: %d\n", m|n) // OR: 14 (1110)
fmt.Printf("m ^ n: %d\n", m^n) // XOR: 6 (0110)
fmt.Printf("m << 1: %d\n", m<<1) // Left shift: 24 (11000)
fmt.Printf("m >> 1: %d\n", m>>1) // Right shift: 6 (110)
}
Exercise 3.1: Variable Practice
Create a Go program that:
- Declares variables of different types
- Performs type conversions
- Uses all arithmetic and comparison operators
- Demonstrates constants and iota
- Shows zero values for different types
Hour 3-4 Summary
You've mastered:
- β
Go variable declaration and initialization
- β
All Go data types and their ranges
- β
Constants and the iota identifier
- β
Type conversions and string parsing
- β
Arithmetic, comparison, logical, and bitwise operators
Hour 5-6: Control Structures & Functions
Conditional Statements
If-Else Statements
package main
import "fmt"
func main() {
score := 85
// Simple if statement
if score >= 90 {
fmt.Println("Excellent! Grade: A")
} else if score >= 80 {
fmt.Println("Good! Grade: B")
} else if score >= 70 {
fmt.Println("Average. Grade: C")
} else if score >= 60 {
fmt.Println("Below Average. Grade: D")
} else {
fmt.Println("Failed. Grade: F")
}
// If with initialization statement
if num := 42; num%2 == 0 {
fmt.Printf("%d is even\n", num)
} else {
fmt.Printf("%d is odd\n", num)
}
// num is not accessible here
// Multiple conditions
age := 25
hasLicense := true
if age >= 18 && hasLicense {
fmt.Println("Can drive")
} else if age >= 18 && !hasLicense {
fmt.Println("Can get a license")
} else {
fmt.Println("Too young to drive")
}
}
Switch Statements
package main
import (
"fmt"
"time"
)
func main() {
// Basic switch
day := time.Now().Weekday()
switch day {
case time.Monday:
fmt.Println("Monday blues π΄")
case time.Tuesday:
fmt.Println("Tuesday grind π")
case time.Wednesday:
fmt.Println("Hump day πͺ")
case time.Thursday:
fmt.Println("Almost there π")
case time.Friday:
fmt.Println("TGIF! π")
case time.Saturday, time.Sunday:
fmt.Println("Weekend! π")
default:
fmt.Println("Unknown day")
}
// Switch with initialization
switch hour := time.Now().Hour(); {
case hour < 12:
fmt.Println("Good morning!")
case hour < 17:
fmt.Println("Good afternoon!")
default:
fmt.Println("Good evening!")
}
// Type switch
var i interface{} = "hello"
switch v := i.(type) {
case int:
fmt.Printf("Integer: %d\n", v)
case string:
fmt.Printf("String: %s\n", v)
case bool:
fmt.Printf("Boolean: %t\n", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
// Switch without expression (like if-else chain)
score := 85
switch {
case score >= 90:
fmt.Println("Grade: A")
case score >= 80:
fmt.Println("Grade: B")
case score >= 70:
fmt.Println("Grade: C")
default:
fmt.Println("Grade: F")
}
}
Loops
For Loops (Go's only loop construct)
package main
import "fmt"
func main() {
// Traditional for loop
fmt.Println("Counting from 1 to 5:")
for i := 1; i <= 5; i++ {
fmt.Printf("%d ", i)
}
fmt.Println()
// For loop as while
fmt.Println("Countdown:")
count := 5
for count > 0 {
fmt.Printf("%d ", count)
count--
}
fmt.Println("Blast off! π")
// Infinite loop (use with break)
fmt.Println("Finding first number divisible by 7:")
num := 1
for {
if num%7 == 0 {
fmt.Printf("Found: %d\n", num)
break
}
num++
}
// For-range with arrays/slices
numbers := []int{10, 20, 30, 40, 50}
fmt.Println("Array elements:")
for index, value := range numbers {
fmt.Printf("Index: %d, Value: %d\n", index, value)
}
// For-range with just values
fmt.Println("Just values:")
for _, value := range numbers {
fmt.Printf("%d ", value)
}
fmt.Println()
// For-range with just indices
fmt.Println("Just indices:")
for index := range numbers {
fmt.Printf("%d ", index)
}
fmt.Println()
// For-range with strings (iterates over runes)
text := "Hello, δΈη"
fmt.Println("String characters:")
for index, char := range text {
fmt.Printf("Index: %d, Char: %c\n", index, char)
}
// For-range with maps
ages := map[string]int{
"Alice": 25,
"Bob": 30,
"Carol": 35,
}
fmt.Println("Map entries:")
for name, age := range ages {
fmt.Printf("%s is %d years old\n", name, age)
}
}
Loop Control
package main
import "fmt"
func main() {
// Break statement
fmt.Println("Using break:")
for i := 1; i <= 10; i++ {
if i == 6 {
fmt.Printf("Breaking at %d\n", i)
break
}
fmt.Printf("%d ", i)
}
fmt.Println()
// Continue statement
fmt.Println("Using continue (skip even numbers):")
for i := 1; i <= 10; i++ {
if i%2 == 0 {
continue // Skip even numbers
}
fmt.Printf("%d ", i)
}
fmt.Println()
// Labeled break and continue (for nested loops)
fmt.Println("Labeled break in nested loops:")
outer:
for i := 1; i <= 3; i++ {
for j := 1; j <= 3; j++ {
if i == 2 && j == 2 {
fmt.Println("Breaking out of both loops")
break outer
}
fmt.Printf("i=%d, j=%d\n", i, j)
}
}
}
Functions
Basic Function Syntax
package main
import "fmt"
// Simple function
func greet() {
fmt.Println("Hello, World!")
}
// Function with parameters
func greetPerson(name string) {
fmt.Printf("Hello, %s!\n", name)
}
// Function with return value
func add(a, b int) int {
return a + b
}
// Function with multiple return values
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
// Function with named return values
func rectangle(length, width float64) (area, perimeter float64) {
area = length * width
perimeter = 2 * (length + width)
return // naked return
}
// Variadic function (variable number of arguments)
func sum(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
// Function as parameter
func calculate(a, b int, operation func(int, int) int) int {
return operation(a, b)
}
func main() {
// Calling functions
greet()
greetPerson("Alice")
result := add(5, 3)
fmt.Printf("5 + 3 = %d\n", result)
quotient, err := divide(10, 3)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Printf("10 / 3 = %.2f\n", quotient)
}
area, perimeter := rectangle(5, 3)
fmt.Printf("Rectangle: area=%.2f, perimeter=%.2f\n", area, perimeter)
total := sum(1, 2, 3, 4, 5)
fmt.Printf("Sum: %d\n", total)
// Anonymous function
multiply := func(a, b int) int {
return a * b
}
result1 := calculate(4, 5, add)
result2 := calculate(4, 5, multiply)
fmt.Printf("4 + 5 = %d\n", result1)
fmt.Printf("4 * 5 = %d\n", result2)
}
Advanced Function Features
package main
import "fmt"
// Closure example
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
// Recursive function
func factorial(n int) int {
if n <= 1 {
return 1
}
return n * factorial(n-1)
}
// Function with defer
func deferExample() {
fmt.Println("Start")
defer fmt.Println("Deferred 1") // Executed last
defer fmt.Println("Deferred 2") // Executed second-to-last
fmt.Println("Middle")
defer fmt.Println("Deferred 3") // Executed first (LIFO order)
fmt.Println("End")
}
func main() {
// Using closure
c1 := counter()
c2 := counter()
fmt.Println("Counter 1:", c1()) // 1
fmt.Println("Counter 1:", c1()) // 2
fmt.Println("Counter 2:", c2()) // 1
fmt.Println("Counter 1:", c1()) // 3
// Using recursive function
fmt.Printf("Factorial of 5: %d\n", factorial(5))
// Defer example
deferExample()
// Defer with function parameters (evaluated immediately)
x := 10
defer fmt.Println("Deferred x:", x) // Will print 10, not 20
x = 20
fmt.Println("Current x:", x)
}
Exercise 5.1: Control Flow Practice
Create Go programs that demonstrate:
- A grade calculator using if-else statements
- A day-of-week detector using switch
- A multiplication table using nested for loops
- A number guessing game using for loop with break
- Processing a slice using for-range
Exercise 5.2: Function Building
Create functions for:
- Calculate factorial using recursion
- Check if a number is prime
- Convert temperature between Celsius and Fahrenheit
- Find maximum and minimum in a slice
- Create a closure that generates Fibonacci numbers
Hour 5-6 Summary
You've learned:
- β
If-else statements with initialization
- β
Switch statements and type switches
- β
For loops and for-range constructs
- β
Loop control with break and continue
- β
Function definition, parameters, and return values
- β
Variadic functions, closures, and recursion
- β
Defer statement for cleanup
Hour 7-8: Arrays, Slices & Maps
Arrays
Arrays in Go have a fixed size and are value types.
package main
import "fmt"
func main() {
// Array declaration and initialization
var numbers [5]int // Zero-valued array
fruits := [3]string{"apple", "banana", "orange"}
scores := [...]int{95, 87, 92, 78, 85} // Compiler determines size
// Accessing array elements
numbers[0] = 10
numbers[1] = 20
fmt.Printf("First number: %d\n", numbers[0])
fmt.Printf("Array length: %d\n", len(numbers))
// Iterating over arrays
fmt.Println("Fruits:")
for i := 0; i < len(fruits); i++ {
fmt.Printf("Index %d: %s\n", i, fruits[i])
}
fmt.Println("Scores:")
for index, score := range scores {
fmt.Printf("Student %d: %d\n", index+1, score)
}
// Multidimensional arrays
var matrix [3][3]int
matrix[0][0] = 1
matrix[1][1] = 2
matrix[2][2] = 3
fmt.Println("Matrix:")
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
fmt.Printf("%d ", matrix[i][j])
}
fmt.Println()
}
// Array comparison
arr1 := [3]int{1, 2, 3}
arr2 := [3]int{1, 2, 3}
arr3 := [3]int{1, 2, 4}
fmt.Printf("arr1 == arr2: %t\n", arr1 == arr2) // true
fmt.Printf("arr1 == arr3: %t\n", arr1 == arr3) // false
}
Slices
Slices are dynamic arrays and are reference types.
package main
import "fmt"
func main() {
// Slice creation
var numbers []int // nil slice
fruits := []string{"apple", "banana"} // slice literal
scores := make([]int, 5) // make with length 5
grades := make([]int, 3, 10) // make with length 3, capacity 10
fmt.Printf("numbers: %v, len: %d, cap: %d\n", numbers, len(numbers), cap(numbers))
fmt.Printf("fruits: %v, len: %d, cap: %d\n", fruits, len(fruits), cap(fruits))
fmt.Printf("scores: %v, len: %d, cap: %d\n", scores, len(scores), cap(scores))
fmt.Printf("grades: %v, len: %d, cap: %d\n", grades, len(grades), cap(grades))
// Appending to slices
numbers = append(numbers, 1, 2, 3)
fruits = append(fruits, "orange", "grape")
fmt.Printf("After append - numbers: %v\n", numbers)
fmt.Printf("After append - fruits: %v\n", fruits)
// Slice operations
data := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Printf("Original: %v\n", data)
fmt.Printf("data[2:5]: %v\n", data[2:5]) // Elements 2, 3, 4
fmt.Printf("data[:4]: %v\n", data[:4]) // Elements 0, 1, 2, 3
fmt.Printf("data[6:]: %v\n", data[6:]) // Elements 6, 7, 8, 9
fmt.Printf("data[:]: %v\n", data[:]) // All elements
// Copying slices
source := []int{1, 2, 3, 4, 5}
destination := make([]int, len(source))
copy(destination, source)
fmt.Printf("Source: %v\n", source)
fmt.Printf("Destination: %v\n", destination)
// Slice tricks
// Remove element at index 2
index := 2
data = append(data[:index], data[index+1:]...)
fmt.Printf("After removing index 2: %v\n", data)
// Insert element at index 3
index = 3
value := 99
data = append(data[:index], append([]int{value}, data[index:]...)...)
fmt.Printf("After inserting 99 at index 3: %v\n", data)
}
Maps
Maps are Go's built-in associative data type (hash tables).
package main
import "fmt"
func main() {
// Map creation
var ages map[string]int // nil map
ages = make(map[string]int) // Initialize empty map
// Map literal
scores := map[string]int{
"Alice": 95,
"Bob": 87,
"Carol": 92,
}
// Adding/updating elements
ages["Alice"] = 25
ages["Bob"] = 30
ages["Carol"] = 35
fmt.Printf("Ages: %v\n", ages)
fmt.Printf("Scores: %v\n", scores)
// Accessing elements
aliceAge := ages["Alice"]
fmt.Printf("Alice's age: %d\n", aliceAge)
// Check if key exists
age, exists := ages["David"]
if exists {
fmt.Printf("David's age: %d\n", age)
} else {
fmt.Println("David not found")
}
// Iterating over maps
fmt.Println("All ages:")
for name, age := range ages {
fmt.Printf("%s: %d\n", name, age)
}
// Deleting elements
delete(ages, "Bob")
fmt.Printf("After deleting Bob: %v\n", ages)
// Map of maps
students := map[string]map[string]int{
"Alice": {"Math": 95, "Science": 87},
"Bob": {"Math": 78, "Science": 92},
}
fmt.Printf("Alice's Math score: %d\n", students["Alice"]["Math"])
// Map with slice values
groups := map[string][]string{
"fruits": {"apple", "banana", "orange"},
"vegetables": {"carrot", "broccoli", "spinach"},
"grains": {"rice", "wheat", "oats"},
}
fmt.Printf("Fruits: %v\n", groups["fruits"])
// Map length
fmt.Printf("Number of groups: %d\n", len(groups))
}
Working with Complex Data Structures
package main
import "fmt"
func main() {
// Slice of maps
employees := []map[string]interface{}{
{"name": "Alice", "age": 30, "salary": 50000.0},
{"name": "Bob", "age": 25, "salary": 45000.0},
{"name": "Carol", "age": 35, "salary": 60000.0},
}
fmt.Println("Employees:")
for i, emp := range employees {
fmt.Printf("Employee %d: %v\n", i+1, emp)
}
// Map of slices
inventory := map[string][]int{
"apples": {10, 15, 20},
"bananas": {5, 8, 12},
"oranges": {7, 9, 11},
}
fmt.Println("Inventory:")
for item, quantities := range inventory {
total := 0
for _, qty := range quantities {
total += qty
}
fmt.Printf("%s: %v (total: %d)\n", item, quantities, total)
}
// Nested data structure
company := map[string]map[string][]string{
"Engineering": {
"Backend": {"Alice", "Bob"},
"Frontend": {"Carol", "David"},
"DevOps": {"Eve"},
},
"Marketing": {
"Digital": {"Frank", "Grace"},
"Traditional": {"Henry"},
},
}
fmt.Println("Company structure:")
for dept, teams := range company {
fmt.Printf("Department: %s\n", dept)
for team, members := range teams {
fmt.Printf(" Team %s: %v\n", team, members)
}
}
}
Exercise 7.1: Data Structure Practice
Create Go programs that:
- Manage a student gradebook using maps and slices
- Implement a simple inventory system
- Create a word frequency counter
- Build a phone book with search functionality
- Process and analyze survey data
Hour 7-8 Summary
You've mastered:
- β
Arrays: fixed-size, value types
- β
Slices: dynamic arrays, reference types
- β
Slice operations: append, copy, slicing
- β
Maps: key-value pairs, hash tables
- β
Complex nested data structures
- β
Iteration patterns with for-range
Hour 9-10: Structs & Methods
Structs
Structs are Go's way of creating custom types that group related data.
package main
import "fmt"
// Struct definition
type Person struct {
Name string
Age int
Email string
Address Address // Embedded struct
}
type Address struct {
Street string
City string
Country string
ZipCode string
}
func main() {
// Struct creation methods
// Method 1: Zero value
var p1 Person
fmt.Printf("Zero value: %+v\n", p1)
// Method 2: Struct literal
p2 := Person{
Name: "Alice",
Age: 30,
Email: "alice@example.com",
Address: Address{
Street: "123 Main St",
City: "New York",
Country: "USA",
ZipCode: "10001",
},
}
// Method 3: Positional initialization (not recommended)
p3 := Person{"Bob", 25, "bob@example.com", Address{"456 Oak Ave", "Boston", "USA", "02101"}}
// Method 4: Partial initialization
p4 := Person{
Name: "Carol",
Age: 35,
// Email and Address will be zero values
}
fmt.Printf("p2: %+v\n", p2)
fmt.Printf("p3: %+v\n", p3)
fmt.Printf("p4: %+v\n", p4)
// Accessing struct fields
fmt.Printf("p2 Name: %s\n", p2.Name)
fmt.Printf("p2 Address City: %s\n", p2.Address.City)
// Modifying struct fields
p2.Age = 31
p2.Address.City = "San Francisco"
fmt.Printf("Modified p2: %+v\n", p2)
// Struct pointers
p5 := &Person{Name: "David", Age: 40}
fmt.Printf("p5: %+v\n", p5)
fmt.Printf("p5 Name: %s\n", p5.Name) // Automatic dereferencing
// Anonymous structs
config := struct {
Host string
Port int
SSL bool
}{
Host: "localhost",
Port: 8080,
SSL: false,
}
fmt.Printf("Config: %+v\n", config)
}
Methods
Methods are functions with a receiver argument.
package main
import (
"fmt"
"math"
)
type Rectangle struct {
Width float64
Height float64
}
type Circle struct {
Radius float64
}
// Method with value receiver
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// Method with value receiver
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
// Method with pointer receiver (can modify the struct)
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
// Method with value receiver
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
// Method with value receiver
func (c Circle) Circumference() float64 {
return 2 * math.Pi * c.Radius
}
// Method with pointer receiver
func (c *Circle) Resize(newRadius float64) {
c.Radius = newRadius
}
// Method that returns multiple values
func (r Rectangle) Dimensions() (float64, float64) {
return r.Width, r.Height
}
// Method with string representation
func (r Rectangle) String() string {
return fmt.Sprintf("Rectangle(%.2f x %.2f)", r.Width, r.Height)
}
func main() {
// Creating instances
rect := Rectangle{Width: 10, Height: 5}
circle := Circle{Radius: 3}
// Calling methods
fmt.Printf("Rectangle area: %.2f\n", rect.Area())
fmt.Printf("Rectangle perimeter: %.2f\n", rect.Perimeter())
fmt.Printf("Circle area: %.2f\n", circle.Area())
fmt.Printf("Circle circumference: %.2f\n", circle.Circumference())
// Methods with pointer receivers
fmt.Printf("Before scaling: %s\n", rect)
rect.Scale(2.0)
fmt.Printf("After scaling: %s\n", rect)
fmt.Printf("Before resizing: Circle(radius=%.2f)\n", circle.Radius)
circle.Resize(5.0)
fmt.Printf("After resizing: Circle(radius=%.2f)\n", circle.Radius)
// Method with multiple return values
w, h := rect.Dimensions()
fmt.Printf("Dimensions: width=%.2f, height=%.2f\n", w, h)
// Methods can be called on pointers too
rectPtr := &Rectangle{Width: 7, Height: 3}
fmt.Printf("Pointer rectangle area: %.2f\n", rectPtr.Area())
}
Struct Embedding and Composition
package main
import "fmt"
// Base structs
type Animal struct {
Name string
Species string
Age int
}
type Mammal struct {
Animal // Embedded struct (anonymous field)
FurColor string
IsWarmBlood bool
}
type Bird struct {
Animal // Embedded struct
CanFly bool
WingSpan float64
}
// Methods on embedded structs
func (a Animal) Speak() string {
return fmt.Sprintf("%s makes a sound", a.Name)
}
func (a Animal) Info() string {
return fmt.Sprintf("%s is a %d-year-old %s", a.Name, a.Age, a.Species)
}
// Methods on embedding structs
func (m Mammal) Speak() string {
return fmt.Sprintf("%s (mammal) makes a mammalian sound", m.Name)
}
func (b Bird) Speak() string {
if b.CanFly {
return fmt.Sprintf("%s chirps while flying", b.Name)
}
return fmt.Sprintf("%s chirps from the ground", b.Name)
}
func (b Bird) Fly() string {
if b.CanFly {
return fmt.Sprintf("%s is flying with a wingspan of %.2f meters", b.Name, b.WingSpan)
}
return fmt.Sprintf("%s cannot fly", b.Name)
}
func main() {
// Creating embedded structs
dog := Mammal{
Animal: Animal{
Name: "Buddy",
Species: "Dog",
Age: 5,
},
FurColor: "Golden",
IsWarmBlood: true,
}
eagle := Bird{
Animal: Animal{
Name: "Freedom",
Species: "Eagle",
Age: 3,
},
CanFly: true,
WingSpan: 2.3,
}
penguin := Bird{
Animal: Animal{
Name: "Waddles",
Species: "Penguin",
Age: 2,
},
CanFly: false,
WingSpan: 0.8,
}
// Accessing embedded fields directly
fmt.Printf("Dog name: %s\n", dog.Name) // Promoted field
fmt.Printf("Dog species: %s\n", dog.Species) // Promoted field
fmt.Printf("Dog fur color: %s\n", dog.FurColor)
// Calling methods
fmt.Println(dog.Speak()) // Calls Mammal's Speak method
fmt.Println(dog.Info()) // Calls Animal's Info method (promoted)
fmt.Println(eagle.Speak()) // Calls Bird's Speak method
fmt.Println(eagle.Fly()) // Calls Bird's Fly method
fmt.Println(eagle.Info()) // Calls Animal's Info method (promoted)
fmt.Println(penguin.Speak())
fmt.Println(penguin.Fly())
// Accessing embedded struct directly
fmt.Printf("Eagle's animal info: %+v\n", eagle.Animal)
}
Exercise 9.1: Library Management System
Create a library system with:
- Book struct with title, author, ISBN, and availability
- Member struct with name, ID, and borrowed books
- Library struct that manages books and members
- Methods for borrowing and returning books
- Methods for searching books and listing members
Hour 9-10 Summary
You've learned:
- β
Struct definition and initialization
- β
Struct field access and modification
- β
Methods with value and pointer receivers
- β
Struct embedding and composition
- β
Method promotion from embedded structs
- β
Anonymous structs for temporary data
Hour 11-12: Interfaces & Polymorphism
Understanding Interfaces
Interfaces in Go define method signatures and enable polymorphism.
package main
import (
"fmt"
"math"
)
// Interface definition
type Shape interface {
Area() float64
Perimeter() float64
}
// Another interface
type Drawable interface {
Draw() string
}
// Combined interface
type DrawableShape interface {
Shape
Drawable
}
// Structs implementing interfaces
type Rectangle struct {
Width, Height float64
}
type Circle struct {
Radius float64
}
// Rectangle implements Shape interface
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
func (r Rectangle) Draw() string {
return fmt.Sprintf("Drawing rectangle %.1fx%.1f", r.Width, r.Height)
}
// Circle implements Shape interface
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}
func (c Circle) Draw() string {
return fmt.Sprintf("Drawing circle with radius %.1f", c.Radius)
}
// Function that accepts interface
func printShapeInfo(s Shape) {
fmt.Printf("Area: %.2f, Perimeter: %.2f\n", s.Area(), s.Perimeter())
}
func drawShape(d Drawable) {
fmt.Println(d.Draw())
}
func main() {
rect := Rectangle{Width: 10, Height: 5}
circle := Circle{Radius: 3}
// Using interfaces for polymorphism
shapes := []Shape{rect, circle}
for i, shape := range shapes {
fmt.Printf("Shape %d:\n", i+1)
printShapeInfo(shape)
// Type assertion to access Draw method
if drawable, ok := shape.(Drawable); ok {
drawShape(drawable)
}
fmt.Println()
}
// Interface variables
var s Shape
s = rect
fmt.Printf("Rectangle area: %.2f\n", s.Area())
s = circle
fmt.Printf("Circle area: %.2f\n", s.Area())
}
Empty Interface and Type Assertions
package main
import "fmt"
// Function that accepts any type
func describe(i interface{}) {
fmt.Printf("Value: %v, Type: %T\n", i, i)
}
// Type assertion examples
func processValue(i interface{}) {
// Type assertion with ok idiom
if str, ok := i.(string); ok {
fmt.Printf("String value: %s (length: %d)\n", str, len(str))
return
}
if num, ok := i.(int); ok {
fmt.Printf("Integer value: %d (squared: %d)\n", num, num*num)
return
}
if f, ok := i.(float64); ok {
fmt.Printf("Float value: %.2f (sqrt: %.2f)\n", f, math.Sqrt(f))
return
}
fmt.Printf("Unknown type: %T\n", i)
}
// Type switch
func classifyValue(i interface{}) {
switch v := i.(type) {
case string:
fmt.Printf("String: %s\n", v)
case int:
fmt.Printf("Integer: %d\n", v)
case float64:
fmt.Printf("Float: %.2f\n", v)
case bool:
fmt.Printf("Boolean: %t\n", v)
case []int:
fmt.Printf("Slice of ints: %v\n", v)
case map[string]int:
fmt.Printf("Map: %v\n", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}
func main() {
// Empty interface can hold any value
var anything interface{}
anything = 42
describe(anything)
anything = "Hello, Go!"
describe(anything)
anything = []int{1, 2, 3}
describe(anything)
// Type assertions
values := []interface{}{
"Hello",
42,
3.14159,
true,
[]int{1, 2, 3},
map[string]int{"a": 1, "b": 2},
}
fmt.Println("\nProcessing values:")
for _, v := range values {
processValue(v)
}
fmt.Println("\nClassifying values:")
for _, v := range values {
classifyValue(v)
}
}
Hour 11-12 Summary
You've learned:
- β
Interface definition and implementation
- β
Polymorphism with interfaces
- β
Empty interface for any type
- β
Type assertions and type switches
- β
Interface composition
Hour 13-14: Goroutines & Concurrency
Introduction to Goroutines
Goroutines are lightweight threads managed by the Go runtime.
package main
import (
"fmt"
"time"
)
func sayHello(name string) {
for i := 0; i < 3; i++ {
fmt.Printf("Hello, %s! (%d)\n", name, i+1)
time.Sleep(100 * time.Millisecond)
}
}
func countNumbers(name string) {
for i := 1; i <= 5; i++ {
fmt.Printf("%s: %d\n", name, i)
time.Sleep(200 * time.Millisecond)
}
}
func main() {
fmt.Println("Sequential execution:")
sayHello("Alice")
sayHello("Bob")
fmt.Println("\nConcurrent execution with goroutines:")
// Start goroutines
go sayHello("Charlie")
go sayHello("David")
go countNumbers("Counter1")
go countNumbers("Counter2")
// Wait for goroutines to complete
time.Sleep(2 * time.Second)
fmt.Println("Main function ending")
}
WaitGroups for Synchronization
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // Decrement counter when function returns
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Duration(id) * 100 * time.Millisecond)
fmt.Printf("Worker %d done\n", id)
}
func processData(data []int, wg *sync.WaitGroup) {
defer wg.Done()
sum := 0
for _, num := range data {
sum += num
time.Sleep(50 * time.Millisecond) // Simulate work
}
fmt.Printf("Sum of %v = %d\n", data, sum)
}
func main() {
var wg sync.WaitGroup
// Example 1: Multiple workers
fmt.Println("Starting workers:")
for i := 1; i <= 5; i++ {
wg.Add(1) // Increment counter
go worker(i, &wg)
}
wg.Wait() // Wait for all goroutines to complete
fmt.Println("All workers completed")
// Example 2: Processing data concurrently
fmt.Println("\nProcessing data:")
datasets := [][]int{
{1, 2, 3, 4, 5},
{10, 20, 30},
{100, 200, 300, 400},
}
for _, data := range datasets {
wg.Add(1)
go processData(data, &wg)
}
wg.Wait()
fmt.Println("All data processing completed")
}
Hour 13-14 Summary
You've learned:
- β
Creating and running goroutines
- β
Concurrent vs sequential execution
- β
WaitGroups for synchronization
- β
Managing goroutine lifecycle
Hour 15-16: Channels & Communication
Channel Basics
package main
import (
"fmt"
"time"
)
func sender(ch chan string) {
messages := []string{"Hello", "World", "From", "Goroutine"}
for _, msg := range messages {
ch <- msg // Send message to channel
time.Sleep(500 * time.Millisecond)
}
close(ch) // Close channel when done
}
func receiver(ch chan string) {
for msg := range ch { // Receive until channel is closed
fmt.Printf("Received: %s\n", msg)
}
}
func main() {
// Create a channel
ch := make(chan string)
// Start sender and receiver goroutines
go sender(ch)
go receiver(ch)
// Wait for completion
time.Sleep(3 * time.Second)
fmt.Println("Communication completed")
}
Hour 15-16 Summary
You've learned:
- β
Channel creation and communication
- β
Sending and receiving data
- β
Channel closing and range loops
- β
Goroutine communication patterns
Hour 17-18: Error Handling & Testing
Error Handling
package main
import (
"errors"
"fmt"
)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
func main() {
result, err := divide(10, 2)
if err != nil {
fmt.Printf("Error: %v\n", err)
} else {
fmt.Printf("Result: %.2f\n", result)
}
result, err = divide(10, 0)
if err != nil {
fmt.Printf("Error: %v\n", err)
} else {
fmt.Printf("Result: %.2f\n", result)
}
}
Hour 17-18 Summary
You've learned:
- β
Error handling patterns
- β
Creating custom errors
- β
Error checking idioms
- β
Testing Go applications
Hour 19-20: Packages & Modules
Creating Packages
// math/calculator.go
package math
func Add(a, b int) int {
return a + b
}
func Multiply(a, b int) int {
return a * b
}
// main.go
package main
import (
"fmt"
"myproject/math"
)
func main() {
result := math.Add(5, 3)
fmt.Printf("5 + 3 = %d\n", result)
result = math.Multiply(4, 7)
fmt.Printf("4 * 7 = %d\n", result)
}
Hour 19-20 Summary
You've learned:
- β
Package creation and organization
- β
Go modules and dependencies
- β
Importing and exporting
- β
Package documentation
Hour 21-22: Web Development with Go
HTTP Server
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
var users = []User{
{ID: 1, Name: "Alice", Email: "alice@example.com"},
{ID: 2, Name: "Bob", Email: "bob@example.com"},
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Welcome to Go Web Server!")
}
func usersHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
}
func main() {
http.HandleFunc("/", homeHandler)
http.HandleFunc("/users", usersHandler)
fmt.Println("Server starting on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Hour 21-22 Summary
You've learned:
- β
HTTP server creation
- β
Routing and handlers
- β
JSON encoding/decoding
- β
Web application structure
Hour 23-24: Complete REST API Project
Final Project: Task Management API
Let's build a complete REST API for task management using everything we've learned.
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"strconv"
"strings"
"sync"
"time"
)
type Task struct {
ID int `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Completed bool `json:"completed"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type TaskManager struct {
tasks map[int]*Task
nextID int
mutex sync.RWMutex
}
func NewTaskManager() *TaskManager {
return &TaskManager{
tasks: make(map[int]*Task),
nextID: 1,
}
}
func (tm *TaskManager) CreateTask(title, description string) *Task {
tm.mutex.Lock()
defer tm.mutex.Unlock()
task := &Task{
ID: tm.nextID,
Title: title,
Description: description,
Completed: false,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
tm.tasks[tm.nextID] = task
tm.nextID++
return task
}
func (tm *TaskManager) GetAllTasks() []*Task {
tm.mutex.RLock()
defer tm.mutex.RUnlock()
tasks := make([]*Task, 0, len(tm.tasks))
for _, task := range tm.tasks {
tasks = append(tasks, task)
}
return tasks
}
func (tm *TaskManager) GetTask(id int) (*Task, bool) {
tm.mutex.RLock()
defer tm.mutex.RUnlock()
task, exists := tm.tasks[id]
return task, exists
}
func (tm *TaskManager) UpdateTask(id int, title, description string, completed *bool) (*Task, bool) {
tm.mutex.Lock()
defer tm.mutex.Unlock()
task, exists := tm.tasks[id]
if !exists {
return nil, false
}
if title != "" {
task.Title = title
}
if description != "" {
task.Description = description
}
if completed != nil {
task.Completed = *completed
}
task.UpdatedAt = time.Now()
return task, true
}
func (tm *TaskManager) DeleteTask(id int) bool {
tm.mutex.Lock()
defer tm.mutex.Unlock()
_, exists := tm.tasks[id]
if exists {
delete(tm.tasks, id)
}
return exists
}
var taskManager = NewTaskManager()
func main() {
// Initialize with sample data
taskManager.CreateTask("Learn Go", "Complete the 24-hour Go learning guide")
taskManager.CreateTask("Build API", "Create a REST API using Go")
http.HandleFunc("/tasks", tasksHandler)
http.HandleFunc("/tasks/", taskHandler)
fmt.Println("Task Management API server starting on :8080")
fmt.Println("Endpoints:")
fmt.Println(" GET /tasks - Get all tasks")
fmt.Println(" POST /tasks - Create new task")
fmt.Println(" GET /tasks/{id} - Get specific task")
fmt.Println(" PUT /tasks/{id} - Update specific task")
fmt.Println(" DELETE /tasks/{id} - Delete specific task")
log.Fatal(http.ListenAndServe(":8080", nil))
}
func tasksHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
getAllTasks(w, r)
case http.MethodPost:
createTask(w, r)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
func taskHandler(w http.ResponseWriter, r *http.Request) {
idStr := strings.TrimPrefix(r.URL.Path, "/tasks/")
id, err := strconv.Atoi(idStr)
if err != nil {
http.Error(w, "Invalid task ID", http.StatusBadRequest)
return
}
switch r.Method {
case http.MethodGet:
getTask(w, r, id)
case http.MethodPut:
updateTask(w, r, id)
case http.MethodDelete:
deleteTask(w, r, id)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
func getAllTasks(w http.ResponseWriter, r *http.Request) {
tasks := taskManager.GetAllTasks()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(tasks)
}
func createTask(w http.ResponseWriter, r *http.Request) {
var req struct {
Title string `json:"title"`
Description string `json:"description"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
if req.Title == "" {
http.Error(w, "Title is required", http.StatusBadRequest)
return
}
task := taskManager.CreateTask(req.Title, req.Description)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(task)
}
func getTask(w http.ResponseWriter, r *http.Request, id int) {
task, exists := taskManager.GetTask(id)
if !exists {
http.Error(w, "Task not found", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(task)
}
func updateTask(w http.ResponseWriter, r *http.Request, id int) {
var req struct {
Title string `json:"title"`
Description string `json:"description"`
Completed *bool `json:"completed"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
task, exists := taskManager.UpdateTask(id, req.Title, req.Description, req.Completed)
if !exists {
http.Error(w, "Task not found", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(task)
}
func deleteTask(w http.ResponseWriter, r *http.Request, id int) {
if !taskManager.DeleteTask(id) {
http.Error(w, "Task not found", http.StatusNotFound)
return
}
w.WriteHeader(http.StatusNoContent)
}
Final Challenge: Complete Task Management API
Enhance the API with:
- User authentication and authorization
- Database persistence (SQLite or PostgreSQL)
- Input validation and error handling
- Logging and middleware
- Unit tests for all endpoints
- API documentation
- Docker containerization
- Rate limiting and security headers
- Pagination for large datasets
- WebSocket support for real-time updates
Hour 23-24 Summary
Congratulations! You've built a complete REST API using:
- β
HTTP server and routing
- β
JSON encoding/decoding
- β
CRUD operations
- β
Concurrent data access with mutexes
- β
RESTful API design principles
- β
Error handling and HTTP status codes
- β
Struct methods and interfaces
- β
Go's built-in HTTP package
π― Resources & Next Steps
Congratulations! π
You've successfully completed the 24-hour Go learning journey! You now have the skills to build concurrent applications and can confidently call yourself a Go developer.
What You've Accomplished
Amazing Progress! In just 24 hours, you've learned:
- Complete Go language mastery
- Concurrent programming with goroutines and channels
- Web development and REST API creation
- Modern Go features and best practices
- Built a complete task management API
Next Steps for Continued Learning
Immediate Next Steps (Week 1-2)
- Practice Daily: Build small Go projects and CLI tools
- Explore Frameworks: Gin, Echo, Fiber for web development
- Join Communities: Go community forums, Reddit r/golang
- Code Reviews: Share your code and get feedback
Intermediate Topics (Month 1-3)
- Advanced concurrency patterns
- Database integration (GORM, sqlx)
- Testing strategies and benchmarking
- gRPC and Protocol Buffers
- Microservices architecture
Advanced Topics (Month 3-6)
- Performance optimization and profiling
- Kubernetes operators in Go
- Distributed systems patterns
- WebAssembly with Go
- Contributing to open source Go projects
Recommended Resources
Official Documentation
Books
- "The Go Programming Language" by Alan Donovan and Brian Kernighan
- "Go in Action" by William Kennedy
- "Concurrency in Go" by Katherine Cox-Buday
- "Go Web Programming" by Sau Sheong Chang
Online Platforms
Project Ideas for Practice
- CLI Tools: Build command-line utilities
- Web Scraper: Create concurrent web scrapers
- Chat Server: Build real-time chat with WebSockets
- File Server: Create a distributed file storage system
- Monitoring Tool: Build system monitoring dashboard
Remember: Go emphasizes simplicity and readability. Always write clear, idiomatic Go code and leverage the language's built-in concurrency features.
Final Tips for Success
- Stay Current: Follow Go releases and new features
- Write Idiomatic Go: Follow Go conventions and best practices
- Embrace Concurrency: Use goroutines and channels effectively
- Test Everything: Write comprehensive tests for your code
- Profile and Optimize: Use Go's built-in profiling tools
- Community: Contribute to the Go ecosystem
You're Now a Gopher! You have the foundation to build scalable, concurrent applications. The journey doesn't end here - continue exploring the Go ecosystem and building amazing projects!