πŸš€ 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) } } */ }