π Go (Golang) Introduction
π― Complete Definition (10 Lines)
Go (Golang) is a statically-typed, compiled programming language designed at
Google by Robert Griesemer, Rob Pike, and Ken Thompson in 2007. Released in 2009,
Go combines simplicity, safety, and performance with built-in concurrency.
Design Philosophy: "Less is more" - minimal syntax, no classes/inheritance,
no exceptions, no generics (until Go 1.18). Compiled to native binaries with fast compilation
and efficient execution.
Key Features: Goroutines (lightweight threads), channels for communication,
garbage collection, interface-based polymorphism, and a comprehensive standard library.
package main
import "fmt"
func main() {
fmt.Println("πΉ Go Master Track - CodeOrbitPro")
fmt.Println("Go: Simple, Fast, Concurrent!")
// Go version check
// $ go version
// go version go1.21.0 linux/amd64
}
π Variables & Data Types
π― Complete Definition (10 Lines)
Go variables are statically typed with type inference via := short
declaration. Zero values: 0 for numbers, false for bool, "" for strings, nil for pointers/interfaces/slices/maps/channels/functions.
Basic types: bool, string, int/int8/int16/int32/int64, uint/uint8/uint16/uint32/uint64/uintptr,
byte (uint8), rune (int32, Unicode), float32/float64, complex64/complex128.
Declaration: var name type = value, name := value (short declaration),
constants with const. Type conversions explicit: Type(value). No implicit type conversions.
package main
import "fmt"
func main() {
// Variable declarations
var name string = "CodeOrbitPro"
var age int = 25
active := true // Short declaration
// Zero values
var score float64
var isDone bool
// Multiple declarations
var x, y int = 10, 20
a, b := 30, "Hello"
// Constants
const Pi = 3.14159
const MaxUsers = 1000
fmt.Println(name, age, active, score, isDone)
fmt.Println(x, y, a, b, Pi)
}
π’ Operators
π― Complete Definition (10 Lines)
Go operators include arithmetic (+, -, *, /, %, ++, --), relational (==, !=, <, >, <=, >=),
logical (&&, ||, !), bitwise (&, |, ^, <<, >>, &^), assignment (=, +=, -=, *=, /=, %=, etc.),
and miscellaneous (sizeof, & address, * pointer, <- channel).
Special operators: No ternary operator (use if-else). := for
short variable declaration. <- for channel operations. & gets address,
* dereferences pointer.
Operator precedence: Unary operators highest, then */%, then +-, then comparisons,
then &&, then ||. Use parentheses for clarity.
package main
import "fmt"
func main() {
a, b := 15, 4
fmt.Println("Arithmetic:")
fmt.Println("a + b =", a + b)
fmt.Println("a / b =", a / b) // Integer division
fmt.Println("a % b =", a % b)
fmt.Println("\nComparison:")
fmt.Println("a > b:", a > b)
fmt.Println("a == b:", a == b)
fmt.Println("\nLogical:")
fmt.Println("true && false:", true && false)
fmt.Println("!true:", !true)
fmt.Println("\nBitwise:")
fmt.Println("a & b:", a & b) // AND
fmt.Println("a | b:", a | b) // OR
fmt.Println("a << 1:", a << 1) // Shift left
// No ternary operator in Go
max := a
if b > a {
max = b
}
fmt.Println("Max:", max)
}
π Control Flow
π― Complete Definition (10 Lines)
Control flow includes if-else, for loops, switch statements, and defer.
Go has only one looping construct: for (used as while, infinite loop, or range-based).
If: Can have initialization statement: if x := compute(); x > 0 {}.
For: Three forms: for i := 0; i < 10; i++ {}, for condition {} (while),
for {} (infinite), for key, value := range collection {}.
Switch: No fall-through by default (use fallthrough keyword).
Can switch on types, values, or expressions. Default case optional.
package main
import "fmt"
func main() {
// If-else with initialization
if x := 42; x > 0 {
fmt.Println("x is positive")
}
// For loops
fmt.Print("Traditional: ")
for i := 0; i < 5; i++ {
fmt.Print(i, " ")
}
fmt.Print("\nWhile style: ")
count := 0
for count < 3 {
fmt.Print(count, " ")
count++
}
// Range-based for
fmt.Print("\nRange loop: ")
nums := []int{10, 20, 30}
for i, num := range nums {
fmt.Printf("[%d]=%d ", i, num)
}
// Switch
grade := 'B'
switch grade {
case 'A':
fmt.Println("\nExcellent!")
case 'B':
fmt.Println("\nGood!")
default:
fmt.Println("\nNeeds improvement")
}
}
βοΈ Functions
π― Complete Definition (10 Lines)
Functions in Go are first-class citizens. Declaration: func name(params) returnType {}.
Multiple return values supported: func f() (int, string) {}. Named return values.
Variadic functions: func sum(nums ...int) int {}. Pass slice with ... suffix.
Functions as values: Can assign to variables, pass as arguments, return from functions.
Anonymous functions (closures) capture surrounding variables.
Defer: defers execution until surrounding function returns. Multiple defers execute
in LIFO order. Used for cleanup (closing files, unlocking mutexes).
package main
import "fmt"
// Basic function
func greet(name string) string {
return "Hello, " + name
}
// Multiple return values
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
// Named returns
func calculate(x, y int) (sum, product int) {
sum = x + y
product = x * y
return // Naked return
}
// Variadic function
func average(nums ...float64) float64 {
total := 0.0
for _, n := range nums {
total += n
}
return total / float64(len(nums))
}
// Function as value
func main() {
fmt.Println(greet("CodeOrbitPro"))
result, err := divide(10, 2)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", result)
}
s, p := calculate(5, 3)
fmt.Printf("Sum: %d, Product: %d\n", s, p)
// Anonymous function
multiply := func(x, y int) int {
return x * y
}
fmt.Println("Anonymous:", multiply(4, 5))
// Defer
defer fmt.Println("This runs last")
defer fmt.Println("This runs second last")
fmt.Println("This runs first")
}
π Arrays & Slices
π― Complete Definition (10 Lines)
Arrays: Fixed-size: var a [5]int. Length part of type. Passed by value (copied).
Slices: Dynamic arrays: []int{1,2,3}. Backed by arrays. Three components:
pointer, length, capacity. Created via make([]T, len, cap), slicing arrays/slices, or literal.
Slice operations: append() adds elements (may reallocate), copy() duplicates slices.
Slicing: s[start:end] (end exclusive). Capacity grows automatically.
Range: for i, v := range slice {} iterates slices. i is index, v is value copy.
package main
import "fmt"
func main() {
// Array (fixed size)
var arr [3]int = [3]int{1, 2, 3}
arr[2] = 42
fmt.Println("Array:", arr, "Length:", len(arr))
// Slice (dynamic)
slice := []int{10, 20, 30}
slice = append(slice, 40, 50)
fmt.Println("Slice:", slice, "Len:", len(slice), "Cap:", cap(slice))
// Slice operations
part := slice[1:3] // [20, 30]
fmt.Println("Subslice:", part)
// Make slice with capacity
nums := make([]int, 0, 5) // len=0, cap=5
nums = append(nums, 1, 2, 3)
fmt.Println("Made slice:", nums)
// Copy slices
dest := make([]int, 3)
copy(dest, slice)
fmt.Println("Copied:", dest)
// 2D slice
matrix := [][]int{
{1, 2, 3},
{4, 5, 6},
}
fmt.Println("2D:", matrix)
}
πΊοΈ Maps
π― Complete Definition (10 Lines)
Maps are hash tables: map[KeyType]ValueType. Zero value is nil (cannot add to nil map).
Created with make() or literal: map[string]int{"a": 1, "b": 2}.
Operations: m[key] = value (insert/update), value = m[key] (retrieve),
delete(m, key) (remove). Two-value assignment tests existence: value, ok := m[key].
Iteration: for key, value := range m {}. Order not guaranteed.
Maps are references - assigned/copied by reference.
Concurrency: Not safe for concurrent access. Use sync.RWMutex or sync.Map.
package main
import "fmt"
func main() {
// Create map
scores := make(map[string]int)
scores["Alice"] = 95
scores["Bob"] = 88
// Literal
ages := map[string]int{
"John": 25,
"Sarah": 30,
}
// Access
fmt.Println("Alice:", scores["Alice"])
// Check existence
if score, ok := scores["Charlie"]; ok {
fmt.Println("Charlie:", score)
} else {
fmt.Println("Charlie not found")
}
// Delete
delete(scores, "Bob")
// Iteration
fmt.Println("\nAll ages:")
for name, age := range ages {
fmt.Printf("%s: %d\n", name, age)
}
// Length
fmt.Println("Map length:", len(ages))
}
ποΈ Structs & Interfaces
π― Complete Definition (10 Lines)
Structs: Collection of fields. No inheritance. Embedding provides composition.
Fields exported if capitalized. Created via literals or new().
Interfaces: Set of method signatures. Implicit implementation - type satisfies
interface by implementing all methods. Empty interface interface{} holds any type.
Type assertions: Extract concrete type: value, ok := interfaceVar.(Type).
Type switches: switch v := x.(type) { case int: ... }.
Embedding: struct { Person; ID int } embeds Person fields/methods.
package main
import "fmt"
// Struct
type Person struct {
Name string
Age int
}
// Method
func (p Person) Greet() string {
return fmt.Sprintf("Hello, I'm %s", p.Name)
}
// Interface
type Greeter interface {
Greet() string
}
// Embedded struct
type Employee struct {
Person
ID int
Salary float64
}
func main() {
// Create struct
p1 := Person{"Alice", 30}
p2 := Person{Name: "Bob", Age: 25}
fmt.Println(p1.Greet())
fmt.Println(p2.Greet())
// Interface
var g Greeter = p1
fmt.Println("Via interface:", g.Greet())
// Type assertion
var val interface{} = 42
if num, ok := val.(int); ok {
fmt.Println("Is int:", num)
}
// Type switch
switch v := val.(type) {
case int:
fmt.Println("Integer:", v)
case string:
fmt.Println("String:", v)
default:
fmt.Println("Unknown type")
}
// Embedded struct
emp := Employee{
Person: Person{"Charlie", 35},
ID: 1001,
Salary: 75000,
}
fmt.Println("Employee:", emp.Name, emp.ID)
}
π― Methods
π― Complete Definition (10 Lines)
Methods are functions with receiver: func (receiver) methodName(params) returns {}.
Receivers can be value or pointer types.
Value receivers: Operate on copy. Cannot modify original struct.
Pointer receivers: Operate on actual instance. Can modify fields.
Go automatically converts between value and pointer for method calls.
Method sets: Type T has methods with receiver T. Type *T has methods with
receivers T and *T. Interface satisfaction depends on method sets.
Non-struct types: Can define methods on any type defined in same package.
package main
import "fmt"
type Rectangle struct {
Width, Height float64
}
// Value receiver (cannot modify)
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// Pointer receiver (can modify)
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
// Method on non-struct type
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
func main() {
rect := Rectangle{Width: 10, Height: 5}
// Call value method
fmt.Println("Area:", rect.Area())
// Call pointer method
rect.Scale(2)
fmt.Println("Scaled:", rect)
fmt.Println("New area:", rect.Area())
// Method on float
f := MyFloat(-3.14)
fmt.Println("Absolute:", f.Abs())
// Method set example
var r1 Rectangle
r1.Scale(1.5) // Go converts &r1 automatically
r2 := &Rectangle{3, 4}
fmt.Println("Area via pointer:", r2.Area()) // Go converts (*r2) automatically
}
β‘ Concurrency
π― Complete Definition (10 Lines)
Goroutines are lightweight threads managed by Go runtime. Created with
go function(). Cheap (2KB stack), multiplexed onto OS threads.
sync package: WaitGroup for waiting goroutines, Mutex/RWMutex for synchronization,
Once for one-time initialization, Cond for condition variables, Pool for object pooling.
Atomic operations: sync/atomic for low-level atomic operations.
Concurrency patterns: Worker pools, fan-in/fan-out, pipeline, heartbeat,
rate limiting, context cancellation.
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
// Launch goroutines
for i := 1; i <= 3; i++ {
wg.Add(1)
go worker(i, &wg)
}
// Wait for all goroutines
wg.Wait()
fmt.Println("All workers completed")
// Mutex example
var counter int
var mu sync.Mutex
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
counter++
mu.Unlock()
}()
}
wg.Wait()
fmt.Println("Counter:", counter)
}
π‘ Channels
π― Complete Definition (10 Lines)
Channels are typed conduits for goroutine communication: make(chan Type, capacity).
Unbuffered (capacity 0) or buffered. Send: ch <- value. Receive: value := <-ch.
Operations: close(ch) closes channel. Range over channel: for v := range ch {}.
select statement for multiple channels. Default case in select for non-blocking operations.
Channel directions: chan T (bidirectional), chan<- T (send-only), <-chan T (receive-only).
Use for function parameters to enforce safety.
Patterns: Fan-in, fan-out, pipeline, timeout, ticker, worker pool.
package main
import (
"fmt"
"time"
)
func producer(ch chan<- int) {
for i := 0; i < 5; i++ {
ch <- i
time.Sleep(100 * time.Millisecond)
}
close(ch)
}
func consumer(id int, ch <-chan int) {
for num := range ch {
fmt.Printf("Consumer %d: %d\n", id, num)
}
}
func main() {
// Unbuffered channel
ch1 := make(chan int)
go func() {
ch1 <- 42
}()
fmt.Println("Received:", <-ch1)
// Buffered channel
ch2 := make(chan int, 3)
ch2 <- 1
ch2 <- 2
ch2 <- 3
fmt.Println("Buffered:", <-ch2, <-ch2, <-ch2)
// Producer-consumer
ch := make(chan int)
go producer(ch)
go consumer(1, ch)
// Select with timeout
select {
case msg := <-ch:
fmt.Println("Got:", msg)
case <-time.After(2 * time.Second):
fmt.Println("Timeout!")
}
// Ticker
ticker := time.NewTicker(500 * time.Millisecond)
done := make(chan bool)
go func() {
for {
select {
case <-done:
return
case t := <-ticker.C:
fmt.Println("Tick at", t)
}
}
}()
time.Sleep(2 * time.Second)
ticker.Stop()
done <- true
fmt.Println("Ticker stopped")
}
π¦ Packages
π― Complete Definition (10 Lines)
Packages organize code. Every Go file begins with package declaration.
Executable packages: package main with main() function. Library packages: any other name.
Exports: Capitalized identifiers are exported (visible outside package).
Lowercase identifiers are private to package.
Import paths: Import "fmt", "math/rand". Aliases: import m "math".
Dot imports: import . "fmt". Blank imports: import _ "database/sql".
Package initialization: init() functions run automatically. Multiple
init() functions in package execute in file order. Import dependencies initialized first.
// main.go
package main
import (
"fmt"
"math"
"math/rand"
"time"
"codeorbitpro/utils" // Custom package
)
// Package-level variables
var version = "1.0.0"
// init function
func init() {
rand.Seed(time.Now().UnixNano())
fmt.Println("Package initialized")
}
func main() {
fmt.Println("π¦ Go Packages Example")
fmt.Println("Version:", version)
// Using standard library
fmt.Println("Pi:", math.Pi)
fmt.Println("Random:", rand.Intn(100))
// Using custom package
result := utils.Add(10, 20)
fmt.Println("Utils add:", result)
// Can't access private function
// utils.privateFunc() // Error: privateFunc not exported
}
// utils/utils.go
package utils
import "fmt"
// Exported function
func Add(a, b int) int {
return a + b
}
// Private function
func privateFunc() {
fmt.Println("This is private")
}
// init in utils
func init() {
fmt.Println("Utils package initialized")
}
π‘οΈ Error Handling
π― Complete Definition (10 Lines)
Errors are values implementing error interface: type error interface { Error() string }.
No exceptions - functions return error as last return value. Callers check errors.
Creating errors: errors.New("message"), fmt.Errorf("format", args).
Custom error types: struct implementing Error() string.
Error handling: if err != nil { handle error }.
Defer-panic-recover: panic() for unrecoverable errors, recover() in defer to catch panics.
Use sparingly - prefer returning errors.
Error wrapping (Go 1.13+): fmt.Errorf("...: %w", err) wraps errors.
errors.Is() and errors.As() for unwrapping.
package main
import (
"errors"
"fmt"
)
// Custom error type
type DivisionError struct {
Dividend float64
Divisor float64
}
func (e DivisionError) Error() string {
return fmt.Sprintf("cannot divide %.2f by %.2f", e.Dividend, e.Divisor)
}
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, DivisionError{a, b}
}
return a / b, nil
}
func process() error {
result, err := divide(10, 0)
if err != nil {
return fmt.Errorf("division failed: %w", err) // Error wrapping
}
fmt.Println("Result:", result)
return nil
}
func main() {
// Basic error checking
if err := process(); err != nil {
fmt.Println("Error:", err)
// Unwrap (Go 1.13+)
var divErr DivisionError
if errors.As(err, &divErr) {
fmt.Println("Dividend:", divErr.Dividend)
}
}
// Panic and recover
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
panic("Something went wrong!")
fmt.Println("This won't execute")
}
π₯ Advanced Go
π― Complete Definition (10 Lines)
Generics (Go 1.18+): Type parameters: func F[T any](t T) {}.
Constraints: type Number interface { int | float64 }. Type inference in calls.
Reflection: reflect package for runtime type inspection. Use sparingly - breaks type safety.
CGo: Call C code from Go. // #include . Build tag constraints.
Testing: go test command. Test files: *_test.go. Benchmark tests,
example tests, table-driven tests. Coverage: go test -cover.
Tooling: gofmt, go vet, golint, go mod, go generate, pprof for profiling.
package main
import (
"fmt"
"reflect"
)
// Generics (Go 1.18+)
func Map[T, U any](slice []T, f func(T) U) []U {
result := make([]U, len(slice))
for i, v := range slice {
result[i] = f(v)
}
return result
}
// Type constraint
type Number interface {
int | float64
}
func Sum[T Number](nums []T) T {
var total T
for _, n := range nums {
total += n
}
return total
}
// Reflection
func printType(v interface{}) {
t := reflect.TypeOf(v)
fmt.Printf("Type: %v, Kind: %v\n", t, t.Kind())
}
func main() {
// Generics
ints := []int{1, 2, 3, 4}
doubled := Map(ints, func(x int) int { return x * 2 })
fmt.Println("Doubled:", doubled)
strings := []string{"a", "b", "c"}
uppercased := Map(strings, func(s string) string {
return s + "!"
})
fmt.Println("Uppercased:", uppercased)
fmt.Println("Sum ints:", Sum([]int{1, 2, 3}))
fmt.Println("Sum floats:", Sum([]float64{1.1, 2.2, 3.3}))
// Reflection
printType(42)
printType("hello")
printType([]int{})
// Testing (would be in *_test.go file)
/*
func TestSum(t *testing.T) {
result := Sum([]int{1, 2, 3})
expected := 6
if result != expected {
t.Errorf("Sum = %d, want %d", result, expected)
}
}
*/
}