Complete development reference
Development// Hello World
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
// Variable declarations
var name string = "Bharath" // explicit type
var age = 25 // type inferred
city := "NYC" // short declaration (inside func only)
// Multiple declarations
var (
x int = 10
y float64 = 3.14
z bool = true
)
// Constants
const Pi = 3.14159
const (
StatusOK = 200
StatusNotFound = 404
)
// iota โ auto-incrementing constants
const (
Sunday int = iota // 0
Monday // 1
Tuesday // 2
)
// Zero values
// int โ 0, float โ 0.0, bool โ false, string โ "", pointer โ nil
// Type conversions (no implicit casting)
i := 42
f := float64(i)
s := string(rune(i))// Basic types
// bool, string
// int, int8, int16, int32, int64
// uint, uint8(byte), uint16, uint32, uint64
// float32, float64
// complex64, complex128
// rune (alias for int32, represents a Unicode code point)
// Struct
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
// Create instances
u1 := User{Name: "Bob", Email: "bob@mail.com"}
u2 := User{"1", "Bob", "bob@mail.com", time.Now()} // positional
u3 := new(User) // returns *User (pointer), zero-valued
// Methods (value receiver)
func (u User) FullName() string {
return u.Name
}
// Methods (pointer receiver โ can mutate)
func (u *User) SetEmail(email string) {
u.Email = email
}
// Embedding (composition over inheritance)
type Admin struct {
User // embedded โ Admin "inherits" User's fields/methods
Role string
}
admin := Admin{User: User{Name: "Alice"}, Role: "super"}
fmt.Println(admin.Name) // promoted field access
// Type aliases & custom types
type UserID int64
type Celsius float64
type StringSlice []string// Basic function
func add(a, b int) int {
return a + b
}
// 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 return values
func swap(a, b int) (x, y int) {
x, y = b, a
return // naked return
}
// Variadic functions
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
// Function as value / first-class
var op func(int, int) int = add
// Anonymous / closure
double := func(n int) int { return n * 2 }
// Higher-order function
func apply(nums []int, fn func(int) int) []int {
result := make([]int, len(nums))
for i, n := range nums {
result[i] = fn(n)
}
return result
}
// Defer โ runs when function returns (LIFO)
func readFile(path string) {
f, _ := os.Open(path)
defer f.Close() // guaranteed cleanup
// ... read file
}
// Init function โ runs before main()
func init() {
// package initialization
}// Interface definition
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// Interface composition
type ReadWriter interface {
Reader
Writer
}
// Implicit implementation โ no "implements" keyword
type MyFile struct{ data []byte }
func (f *MyFile) Read(p []byte) (int, error) {
copy(p, f.data)
return len(f.data), nil
}
// *MyFile now satisfies Reader interface
// Empty interface โ accepts any type
var anything interface{} = "hello"
var anything2 any = 42 // 'any' is alias for interface{} (Go 1.18+)
// Type assertion
val, ok := anything.(string)
if ok {
fmt.Println(val)
}
// Type switch
func describe(i interface{}) string {
switch v := i.(type) {
case int:
return fmt.Sprintf("int: %d", v)
case string:
return fmt.Sprintf("string: %s", v)
default:
return "unknown"
}
}
// Stringer interface (like toString)
func (u User) String() string {
return fmt.Sprintf("%s (%s)", u.Name, u.Email)
}// Array (fixed size)
var arr [5]int = [5]int{1, 2, 3, 4, 5}
// Slice (dynamic, backed by array)
s := []int{1, 2, 3}
s = append(s, 4, 5) // append elements
s = append(s, other...) // append another slice
// Make with length & capacity
s2 := make([]int, 0, 100) // len=0, cap=100
// Slicing
sub := s[1:3] // [2, 3] โ shares underlying array!
cpy := make([]int, len(s))
copy(cpy, s) // true copy
// Delete element at index i (Go 1.21+: slices.Delete)
s = append(s[:i], s[i+1:]...)
// Maps
m := map[string]int{
"one": 1,
"two": 2,
}
m["three"] = 3 // set
val, ok := m["one"] // get with existence check
delete(m, "two") // delete key
// Iterate
for key, val := range m {
fmt.Println(key, val)
}
// Iterate slice
for i, v := range s {
fmt.Println(i, v)
}
// Useful packages (Go 1.21+)
import "slices"
slices.Sort(s)
slices.Contains(s, 3)
idx := slices.Index(s, 3)
import "maps"
keys := maps.Keys(m)
maps.Clone(m)// If (no parentheses, braces required)
if x > 0 {
fmt.Println("positive")
} else if x == 0 {
fmt.Println("zero")
} else {
fmt.Println("negative")
}
// If with init statement
if err := doSomething(); err != nil {
log.Fatal(err)
}
// For loop (Go's only loop)
for i := 0; i < 10; i++ { }
// While-style
for condition { }
// Infinite loop
for { break }
// Range loop
for i, v := range slice { }
for k, v := range myMap { }
for i, ch := range "hello" { } // iterates runes
// Switch (no break needed โ implicit)
switch day {
case "Mon", "Tue", "Wed", "Thu", "Fri":
fmt.Println("weekday")
case "Sat", "Sun":
fmt.Println("weekend")
default:
fmt.Println("invalid")
}
// Switch without condition (cleaner if/else chain)
switch {
case t.Hour() < 12:
fmt.Println("morning")
case t.Hour() < 17:
fmt.Println("afternoon")
default:
fmt.Println("evening")
}
// Select (switch for channels)
select {
case msg := <-ch1:
fmt.Println(msg)
case ch2 <- data:
fmt.Println("sent")
case <-time.After(5 * time.Second):
fmt.Println("timeout")
}// Start a goroutine
go doWork()
// Anonymous goroutine
go func(msg string) {
fmt.Println(msg)
}("hello")
// WaitGroup โ wait for goroutines to finish
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
fmt.Println("worker", id)
}(i)
}
wg.Wait()
// Unbuffered channel (synchronous)
ch := make(chan int)
go func() { ch <- 42 }()
val := <-ch
// Buffered channel
ch := make(chan string, 10) // buffer size 10
ch <- "msg" // won't block until buffer full
// Directional channels
func producer(out chan<- int) { out <- 1 } // send-only
func consumer(in <-chan int) { <-in } // receive-only
// Range over channel
go func() {
for i := 0; i < 5; i++ { ch <- i }
close(ch) // must close for range to exit
}()
for val := range ch {
fmt.Println(val)
}type SafeCounter struct {
mu sync.Mutex
count int
}
func (c *SafeCounter) Inc() {
c.mu.Lock()
defer c.mu.Unlock()
c.count++
}
// RWMutex โ multiple readers, single writer
var rw sync.RWMutex
rw.RLock() // read lock
rw.RUnlock()// Timeout context
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Cancel context
ctx, cancel := context.WithCancel(context.Background())
// Use in goroutine
go func(ctx context.Context) {
select {
case <-ctx.Done():
fmt.Println("cancelled:", ctx.Err())
return
case result := <-doWork(ctx):
fmt.Println(result)
}
}(ctx)func workerPool(jobs <-chan int, results chan<- int, workers int) {
var wg sync.WaitGroup
for w := 0; w < workers; w++ {
wg.Add(1)
go func() {
defer wg.Done()
for job := range jobs {
results <- job * 2
}
}()
}
wg.Wait()
close(results)
}import "golang.org/x/sync/errgroup"
g, ctx := errgroup.WithContext(context.Background())
g.Go(func() error { return fetchA(ctx) })
g.Go(func() error { return fetchB(ctx) })
if err := g.Wait(); err != nil {
log.Fatal(err) // first error cancels all
}// Basic error check (the Go way)
result, err := doSomething()
if err != nil {
return fmt.Errorf("failed to do something: %w", err) // wrap error
}
// Custom error type
type NotFoundError struct {
ID string
Kind string
}
func (e *NotFoundError) Error() string {
return fmt.Sprintf("%s %s not found", e.Kind, e.ID)
}
// Sentinel errors
var ErrNotFound = errors.New("not found")
var ErrUnauthorized = errors.New("unauthorized")
// errors.Is โ check error chain
if errors.Is(err, ErrNotFound) {
// handle not found
}
// errors.As โ extract typed error
var nfErr *NotFoundError
if errors.As(err, &nfErr) {
fmt.Println(nfErr.Kind, nfErr.ID)
}
// Panic & Recover (use sparingly โ not for normal errors)
func safeDiv(a, b int) (int, error) {
defer func() {
if r := recover(); r != nil {
fmt.Println("recovered:", r)
}
}()
return a / b, nil
}// Read entire file
data, err := os.ReadFile("file.txt")
// Write file
err := os.WriteFile("out.txt", []byte("hello"), 0644)
// Buffered reading
f, _ := os.Open("file.txt")
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
// JSON encode/decode
import "encoding/json"
// Struct โ JSON
jsonBytes, _ := json.Marshal(user)
jsonStr := string(jsonBytes)
// JSON โ Struct
var u User
json.Unmarshal([]byte(jsonStr), &u)
// Pretty print
jsonBytes, _ := json.MarshalIndent(user, "", " ")
// Streaming JSON
encoder := json.NewEncoder(os.Stdout)
encoder.Encode(user)
decoder := json.NewDecoder(resp.Body)
decoder.Decode(&u)import "net/http"
// Simple HTTP server
func main() {
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s!", r.URL.Query().Get("name"))
})
http.ListenAndServe(":8080", nil)
}
// JSON API handler
func getUser(w http.ResponseWriter, r *http.Request) {
user := User{Name: "Bob", Email: "bob@mail.com"}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
}
// HTTP client
resp, err := http.Get("https://api.example.com/data")
if err != nil { log.Fatal(err) }
defer resp.Body.Close()
var data Response
json.NewDecoder(resp.Body).Decode(&data)
// HTTP client with timeout
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Get("https://api.example.com")
// Middleware pattern
func logging(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
})
}// file: math_test.go
package math
import "testing"
// Basic test
func TestAdd(t *testing.T) {
got := Add(2, 3)
want := 5
if got != want {
t.Errorf("Add(2, 3) = %d, want %d", got, want)
}
}
// Table-driven tests (idiomatic Go)
func TestDivide(t *testing.T) {
tests := []struct {
name string
a, b float64
want float64
wantErr bool
}{
{"ok", 10, 2, 5, false},
{"div by zero", 10, 0, 0, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Divide(tt.a, tt.b)
if (err != nil) != tt.wantErr {
t.Errorf("unexpected error: %v", err)
}
if got != tt.want {
t.Errorf("got %v, want %v", got, tt.want)
}
})
}
}
// Benchmark
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(2, 3)
}
}
// Run: go test ./...
// Run: go test -v -run TestAdd
// Run: go test -bench=.// Generic function
func Map[T, U any](s []T, fn func(T) U) []U {
result := make([]U, len(s))
for i, v := range s {
result[i] = fn(v)
}
return result
}
// Constrained generic
type Number interface {
~int | ~int64 | ~float64
}
func Sum[T Number](nums []T) T {
var total T
for _, n := range nums {
total += n
}
return total
}
// comparable constraint
func Contains[T comparable](s []T, target T) bool {
for _, v := range s {
if v == target { return true }
}
return false
}
// Generic struct
type Stack[T any] struct {
items []T
}
func (s *Stack[T]) Push(item T) { s.items = append(s.items, item) }
func (s *Stack[T]) Pop() (T, bool) {
if len(s.items) == 0 {
var zero T
return zero, false
}
item := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return item, true
}# Initialize module
go mod init github.com/user/myproject
# Add dependency
go get github.com/gin-gonic/gin@latest
# Tidy โ remove unused, add missing
go mod tidy
# Vendor dependencies
go mod vendor
# Common project structure
myproject/
โโโ cmd/
โ โโโ server/
โ โโโ main.go # entry point
โโโ internal/ # private packages
โ โโโ handler/
โ โโโ service/
โ โโโ repository/
โโโ pkg/ # public packages
โ โโโ utils/
โโโ go.mod
โโโ go.sum
โโโ MakefileUser, GetName()user, getName()http, json-er โ Reader, Writertype Option func(*Server)
func WithPort(port int) Option {
return func(s *Server) { s.port = port }
}
func WithTimeout(d time.Duration) Option {
return func(s *Server) { s.timeout = d }
}
func NewServer(opts ...Option) *Server {
s := &Server{port: 8080, timeout: 30 * time.Second}
for _, opt := range opts { opt(s) }
return s
}
srv := NewServer(WithPort(3000), WithTimeout(10*time.Second))type UserRepository interface {
FindByID(ctx context.Context, id string) (*User, error)
Create(ctx context.Context, user *User) error
Update(ctx context.Context, user *User) error
Delete(ctx context.Context, id string) error
}
type pgUserRepo struct { db *sql.DB }
func (r *pgUserRepo) FindByID(ctx context.Context, id string) (*User, error) {
var u User
err := r.db.QueryRowContext(ctx, "SELECT * FROM users WHERE id=$1", id).Scan(&u.ID, &u.Name)
return &u, err
}