Title: Go Programming — LearnCoachAssist

Q: What is Go (Golang)?
A: Go is an open-source programming language developed at Google by Robert Griesemer, Rob Pike, and Ken Thompson. It is statically typed, compiled, and designed for simplicity, concurrency, and performance.

Q: How do you declare a variable in Go?
A: You can declare variables using:
var x int = 10
var y = "hello" (type inferred)
z := 42 (short declaration, only inside functions)

Q: What is a goroutine?
A: A goroutine is a lightweight thread managed by the Go runtime. You start one with the go keyword:
go myFunction()
Goroutines are multiplexed onto OS threads and are extremely cheap to create (only a few KB of stack).

Q: How do you create a channel in Go?
A: Use the make function:
ch := make(chan int) — unbuffered
ch := make(chan string, 5) — buffered with capacity 5
Channels are used to communicate between goroutines safely.

Q: What is the difference between unbuffered and buffered channels?
A: Unbuffered channels block the sender until the receiver is ready, and vice versa — they provide synchronization.
Buffered channels allow sending up to their capacity without blocking. The sender only blocks when the buffer is full.

Q: How do interfaces work in Go?
A: Interfaces in Go are satisfied implicitly — a type implements an interface by implementing all its methods, with no explicit declaration needed:
type Stringer interface { String() string }
Any type with a String() string method satisfies Stringer.

Q: How does error handling work in Go?
A: Go uses explicit error returns instead of exceptions:
result, err := doSomething()
if err != nil { log.Fatal(err) }
The error type is a built-in interface: type error interface { Error() string }

Q: What is a package in Go?
A: A package is Go's way of organizing code. Every Go file starts with package name. The main package with a func main() is the entry point. Exported identifiers start with an uppercase letter.

Q: How do slices work in Go?
A: A slice is a dynamically-sized, flexible view into an array:
s := []int{1, 2, 3}
s = append(s, 4)
Slices have a length (len(s)) and capacity (cap(s)). They reference an underlying array.

Q: How do you use maps in Go?
A: Maps are key-value collections:
m := make(map[string]int)
m["age"] = 30
val, ok := m["age"] — the comma ok idiom checks if a key exists. Maps are not safe for concurrent access without synchronization.

Q: What is a struct in Go?
A: A struct is a composite type that groups fields:
type Person struct {
  Name string
  Age int
}
p := Person{Name: "Alice", Age: 30}

Q: How do methods work in Go?
A: Methods are functions with a receiver argument:
func (p Person) Greet() string {
  return "Hi, " + p.Name
}
Use a pointer receiver (p *Person) to modify the struct or avoid copying.

Q: What does the defer keyword do?
A: defer schedules a function call to run after the surrounding function returns. Deferred calls are executed in LIFO order:
defer fmt.Println("done")
Common uses: closing files, unlocking mutexes, cleanup tasks.

Q: How do pointers work in Go?
A: A pointer holds the memory address of a value:
x := 42
p := &x — p is a pointer to x
*p = 100 — dereference to modify
Go has no pointer arithmetic, making pointers safer than in C.

Q: What is the select statement in Go?
A: select lets a goroutine wait on multiple channel operations:
select {
case msg := <-ch1:
  fmt.Println(msg)
case ch2 <- 42:
  fmt.Println("sent")
default:
  fmt.Println("no activity")
}

Q: How do you write tests in Go?
A: Create a file ending in _test.go and use the testing package:
func TestAdd(t *testing.T) {
  if Add(2, 3) != 5 {
    t.Error("expected 5")
  }
}
Run with go test ./...

Q: What are Go modules?
A: Go modules are the dependency management system introduced in Go 1.11. Initialize with go mod init module-name. The go.mod file tracks dependencies and their versions. Use go mod tidy to clean up.

Q: What is a type assertion in Go?
A: A type assertion extracts the underlying concrete type from an interface:
val, ok := i.(string)
If ok is true, val holds the string. Without the comma-ok pattern, a failed assertion causes a panic.

Q: What is the empty interface in Go?
A: The empty interface interface{} (or any in Go 1.18+) has zero methods, so every type satisfies it. It is used for generic containers:
func Print(val any) { fmt.Println(val) }
Use type assertions or type switches to extract the concrete value.

Q: How does the range keyword work?
A: range iterates over slices, maps, strings, and channels:
for i, v := range slice { ... }
for k, v := range myMap { ... }
for val := range ch { ... }
Use _ to discard an unwanted index or value.

Q: What is a type switch in Go?
A: A type switch inspects the concrete type of an interface value:
switch v := i.(type) {
case int:
  fmt.Println("int:", v)
case string:
  fmt.Println("string:", v)
default:
  fmt.Println("unknown")
}

Q: How do you handle panics in Go?
A: Use recover() inside a deferred function to catch panics:
defer func() {
  if r := recover(); r != nil {
    fmt.Println("recovered:", r)
  }
}()
panic("something went wrong")

Q: What is the init function in Go?
A: func init() runs automatically before main(). Each file can have multiple init functions. They are used for:
- Setting up initial state
- Registering drivers or plugins
- Validating configuration

Q: What are Go's basic data types?
A: Go's basic types include:
- bool
- string
- int, int8, int16, int32, int64
- uint, uint8, uint16, uint32, uint64
- float32, float64
- complex64, complex128
- byte (alias for uint8), rune (alias for int32)

Q: What is the difference between make and new in Go?
A: new(T) allocates memory for type T and returns a pointer *T initialized to zero value.
make(T, args) is used only for slices, maps, and channels — it returns an initialized (not zeroed) value of type T, not a pointer.

Q: How do you create a custom error in Go?
A: Implement the error interface:
type MyError struct { Code int; Msg string }
func (e *MyError) Error() string {
  return fmt.Sprintf("%d: %s", e.Code, e.Msg)
}
Or use fmt.Errorf("wrap: %w", err) for error wrapping.

Q: What is the WaitGroup in Go?
A: sync.WaitGroup waits for a collection of goroutines to finish:
var wg sync.WaitGroup
wg.Add(1)
go func() { defer wg.Done(); work() }()
wg.Wait()
It acts as a concurrent counter.

Q: How do you close a channel and why?
A: Use close(ch) to signal that no more values will be sent. Receivers can detect this:
val, ok := <-ch — ok is false when closed.
A for range ch loop exits automatically when the channel is closed. Only the sender should close a channel.

Q: What is a goroutine leak?
A: A goroutine leak occurs when a goroutine is blocked forever (e.g., waiting on a channel that is never closed or written to). This wastes memory. Prevent leaks by:
- Using context.Context for cancellation
- Always closing channels when done
- Using select with a done channel

Q: How does the context package work?
A: The context package manages deadlines, cancellation, and request-scoped values:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
Pass ctx to functions and check ctx.Done() for cancellation.

Q: What is struct embedding in Go?
A: Go supports composition over inheritance via struct embedding:
type Animal struct { Name string }
type Dog struct { Animal; Breed string }
d := Dog{Animal{"Rex"}, "Labrador"}
d.Name is promoted — accessible directly on Dog.

Q: What is the difference between value and pointer receivers?
A: A value receiver (t T) works on a copy of the struct — modifications don't affect the original.
A pointer receiver (t *T) works on the original — it can modify fields and avoids copying large structs.

Q: How do you use the fmt package for formatting?
A: Key fmt verbs:
- %v — default format
- %+v — struct with field names
- %#v — Go syntax representation
- %T — type of value
- %d — integer
- %s — string
- %f — float
- %p — pointer address

Q: What is the zero value in Go?
A: Every type in Go has a zero value — the default when no value is assigned:
- int → 0
- float64 → 0.0
- bool → false
- string → ""
- pointers, slices, maps, channels, interfaces → nil

Q: How do you implement the Stringer interface?
A: Implement String() string from the fmt package:
func (p Person) String() string {
  return fmt.Sprintf("%s (%d years)", p.Name, p.Age)
}
Now fmt.Println(p) uses your custom format automatically.

Q: What is the mutex in Go?
A: sync.Mutex provides mutual exclusion for shared data:
var mu sync.Mutex
mu.Lock()
// critical section
mu.Unlock()
Use sync.RWMutex for multiple readers with a single writer pattern. Always use defer mu.Unlock() for safety.

Q: How do you work with JSON in Go?
A: Use the encoding/json package:
data, err := json.Marshal(myStruct) — struct to JSON
err := json.Unmarshal(data, &myStruct) — JSON to struct
Use struct tags: Name string `json:"name,omitempty"` to control field names and behavior.

Q: What is a slice of slices (2D slice) in Go?
A: Create a 2D slice manually:
matrix := make([][]int, rows)
for i := range matrix {
  matrix[i] = make([]int, cols)
}
Go does not have built-in multidimensional arrays with dynamic sizes, so you compose slices of slices.

Q: What is the iota keyword in Go?
A: iota is a constant generator used in const blocks. It starts at 0 and increments by 1:
const (
  Red = iota // 0
  Green // 1
  Blue // 2
)
Useful for creating enumerations in Go.

Q: What is the difference between arrays and slices in Go?
A: Arrays have a fixed size that is part of their type: [3]int.
Slices are dynamically sized references to arrays: []int.
Slices are far more common. You can create a slice from an array: s := arr[1:3].

Q: How do you use the go keyword for concurrency?
A: Prefix a function call with go to run it as a goroutine:
go func() {
  fmt.Println("running concurrently")
}()
The calling function does not wait for the goroutine to finish — use channels or sync.WaitGroup for synchronization.

Q: What are table-driven tests in Go?
A: A common Go testing pattern using a slice of test cases:
tests := []struct{ input int; want int }{
  {1, 2}, {2, 4},
}
for _, tt := range tests {
  t.Run(fmt.Sprint(tt.input), func(t *testing.T) {
    if got := Double(tt.input); got != tt.want {
      t.Errorf("got %d, want %d", got, tt.want)
    }
  })
}

Q: What is the errors.Is and errors.As pattern?
A: Introduced in Go 1.13 for error wrapping:
errors.Is(err, target) — checks if any error in the chain matches target
errors.As(err, &target) — finds the first error matching the target type
Wrap errors with fmt.Errorf("context: %w", err).

Q: What is a fan-out fan-in concurrency pattern?
A: Fan-out: multiple goroutines read from the same channel to distribute work.
Fan-in: a single goroutine reads from multiple input channels and merges them into one output channel.
This pattern is used to parallelize work and then collect results.

Q: What is the difference between concurrency and parallelism in Go?
A: Concurrency is about structuring a program to handle multiple tasks (goroutines, channels).
Parallelism is about executing multiple tasks simultaneously on multiple CPU cores.
Go makes concurrency easy; parallelism depends on GOMAXPROCS and available cores.

Q: How do you use the http package in Go?
A: The net/http package provides a built-in web server:
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintln(w, "Hello!")
})
http.ListenAndServe(":8080", nil)
It also provides an HTTP client: resp, err := http.Get("https://example.com")

Q: What are Go workspace commands?
A: Key go commands:
- go build — compile packages
- go run — compile and execute
- go test — run tests
- go fmt — format source code
- go vet — report suspicious constructs
- go mod init — initialize a module
- go get — add dependencies

Q: What is a closure in Go?
A: A closure is a function that captures variables from its surrounding scope:
func counter() func() int {
  n := 0
  return func() int { n++; return n }
}
c := counter()
c() // 1
c() // 2
The returned function retains access to n.

Q: How do you use generics in Go?
A: Generics were added in Go 1.18 with type parameters:
func Map[T any, U any](s []T, f func(T) U) []U {
  result := make([]U, len(s))
  for i, v := range s {
    result[i] = f(v)
  }
  return result
}
Use type constraints to restrict allowed types.

Q: What is the difference between exported and unexported identifiers?
A: In Go, an identifier starting with an uppercase letter is exported (public) — accessible from other packages.
A lowercase identifier is unexported (private) — only accessible within its own package.
Example: Person is exported; person is unexported.

Q: How does Go's garbage collector work?
A: Go uses a concurrent, tri-color mark-and-sweep garbage collector. It runs concurrently with the program, uses a write barrier to maintain correctness, and since Go 1.8 has sub-millisecond pause times. It is tuned by GOGC (default 100) which controls the heap growth ratio before triggering a collection.

Q: What is GOMAXPROCS?
A: GOMAXPROCS is an environment variable / function that sets the maximum number of OS threads that can execute Go code simultaneously. Default = runtime.NumCPU(). It limits parallelism, not concurrency — goroutines can still exist in greater numbers.

Q: What is the scheduler's M:N model in Go?
A: Go's runtime uses an M:N scheduler that maps M goroutines onto N OS threads. Components:
- G = goroutine
- M = OS thread (machine)
- P = logical processor holding a run queue
Work stealing between Ps keeps load balanced.

Q: What is a Go runtime.Gosched call?
A: runtime.Gosched() yields the current goroutine, allowing the scheduler to run other goroutines. The yielding goroutine is automatically resumed later. Useful when a tight loop might starve other goroutines.

Q: What is a deadlock and how does Go detect it?
A: A deadlock occurs when all goroutines are blocked waiting on each other. The Go runtime detects this and panics with fatal error: all goroutines are asleep - deadlock! Detection only works if all goroutines are blocked.

Q: What is the race detector in Go?
A: Enabled with go test -race or go run -race. It instruments memory accesses using ThreadSanitizer to detect data races at runtime. Adds ~5–10x overhead and ~2–20x memory cost, so use it in tests rather than production.

Q: What is a data race?
A: A data race occurs when two goroutines access the same variable concurrently, at least one access is a write, and there is no synchronization between them. Races cause undefined behavior in Go's memory model. Fix with mutexes, channels, or sync/atomic.

Q: What is the sync/atomic package used for?
A: sync/atomic provides lock-free low-level atomic operations on memory: atomic.AddInt64, atomic.LoadInt32, atomic.StorePointer, atomic.CompareAndSwap. Use for counters and flags where a mutex would be overkill.

Q: What is the difference between sync.Mutex and sync.RWMutex?
A: sync.Mutex is exclusive — one lock holder at a time.
sync.RWMutex allows multiple concurrent readers but only one writer. Call RLock()/RUnlock() for reads, Lock()/Unlock() for writes. Use RWMutex when reads dominate.

Q: What is sync.Once?
A: sync.Once ensures a function runs exactly once even across many goroutines:
var once sync.Once
once.Do(initFunc)
Common uses: lazy initialization, one-time setup.

Q: What is sync.Pool?
A: sync.Pool is a cache of temporary objects designed to reduce allocation pressure. pool.Get() returns an object (creating one if needed), pool.Put(x) returns it. Pools are cleared at every GC, so do not rely on them for persistent state.

Q: What is sync.Cond?
A: sync.Cond implements a condition variable — goroutines wait for or announce that a condition has occurred:
cond.L.Lock(); cond.Wait(); cond.Signal(); cond.Broadcast(). Rarely used directly; channels are usually preferred.

Q: What is the difference between cap and len for a slice?
A: len(s) is the number of elements currently in the slice.
cap(s) is the number of elements in the underlying array starting from the slice's first element. Appending beyond capacity allocates a new underlying array.

Q: How does append grow a slice?
A: When a slice has no spare capacity, append allocates a new underlying array. Growth strategy (Go 1.18+) typically doubles for small slices and grows by ~25% for larger ones (capped at 256), then follows a formula. This is amortized O(1) but causes occasional spikes.

Q: What is the difference between copy and assignment for slices?
A: a := b makes a and b share the same underlying array — changes to one are visible in the other.
copy(dst, src) copies elements into independent backing storage. The copy size is min(len(dst), len(src)).

Q: What is a nil slice vs an empty slice?
A: Nil slice: var s []int → s == nil, length 0.
Empty slice: s := []int{} or make([]int, 0) → s != nil, length 0.
Most operations (range, append, len) behave identically. json.Marshal renders nil as null and empty as [].

Q: How do you delete a key from a map?
A: Use the built-in delete function:
delete(m, "key")
It is a no-op if the key does not exist. Deleting during iteration is safe in Go.

Q: What happens if you read a missing key from a map?
A: Reading a missing key returns the zero value of the value type — it does not panic:
val := m["nope"] // val is ""
Use the comma-ok idiom val, ok := m["key"] to distinguish missing from zero.

Q: Can you take the address of a map element?
A: No. Map elements are not addressable. &m["key"] is a compile-time error. To modify a map element you must assign back: m["key"] = newValue.

Q: How do you sort a slice in Go?
A: Use sort.Ints(s) (or sort.Strings, sort.Float64s). For custom types implement sort.Interface with Len, Less, Swap, then call sort.Sort(s).
For Go 1.21+, slices.Sort(s) from the slices package is preferred.

Q: What is the sort.Slice function?
A: sort.Slice(s, func(i, j int) bool { return s[i] < s[j] }) sorts in place using a custom less function. Note: it is not guaranteed stable. For a stable sort, use sort.SliceStable with the same signature.

Q: What is sort.SliceStable used for?
A: sort.SliceStable preserves the relative order of equal elements. Useful when sorting a slice of structs by one field while keeping secondary fields in their original order. Underlying algorithm is insertion sort (O(n²) worst case).

Q: How do you check if a slice contains an element?
A: In Go 1.21+, use slices.Contains(s, v). Before that, write a loop:
for _, x := range s {
  if x == v { return true }
}
or use sort.Search on a sorted slice for O(log n) lookup.

Q: What is the strings.Builder type?
A: strings.Builder is an efficient way to concatenate many strings:
var b strings.Builder
b.WriteString("hello")
b.String()
It avoids the O(n²) cost of repeated str = str + x by using a growing byte buffer.

Q: What is the strings.Repeat function?
A: strings.Repeat(s, count) returns a new string consisting of count copies of s:
strings.Repeat("ab", 3) → "ababab"
If count is negative or the result overflows, it panics.

Q: What does strings.SplitN do differently from strings.Split?
A: strings.Split(s, sep) splits into all substrings.
strings.SplitN(s, sep, n) splits into at most n substrings, with the last containing the unsplit remainder. strings.SplitN(s, sep, -1) is equivalent to Split.

Q: What is the difference between nil and empty strings?
A: Nil string: there is no string; the variable is nil (only possible for uninitialized interface/pointer contexts).
Empty string "": a string with length 0 but not nil. The zero value of string is "", not nil — strings are values, not references.

Q: How do you convert between strings and byte slices?
A: []byte("hello") — string to byte slice (allocates and copies).
string(b) — byte slice to string (allocates and copies).
In Go 1.20+, conversion to []byte no longer escapes in some cases, reducing allocations. Use unsafe only with extreme care.

Q: What is a rune in Go?
A: A rune is an alias for int32 that represents a single Unicode code point. Use it for individual characters: r := 'é' (note single quotes). Iterating a string with range yields runes and byte indices, not bytes.

Q: What is the difference between len(s) and utf8.RuneCountInString(s)?
A: len(s) returns the byte length of the string.
utf8.RuneCountInString(s) returns the number of runes (Unicode code points). For ASCII they are equal; for non-ASCII strings (e.g. emojis, accented chars) they differ.

Q: How do you write a string with Unicode escapes?
A: Go string literals support: \x (2 hex digits), \u (4 hex digits, Unicode), \U (8 hex digits), \nnn (octal).
"\u00e9" → "é"
Raw string literals (backticks) interpret no escapes.

Q: What is the difference between single-quoted and double-quoted string literals?
A: Double-quoted strings interpret escape sequences: "a\nb" is 3 bytes.
Single-quoted literals denote a rune (an int32 value), not a string: 'a' is the integer 97.
Backtick raw strings interpret nothing and can span multiple lines.

Q: What is the time package's time.Time type?
A: time.Time represents an instant with nanosecond precision. It is a value type that should usually be passed by value or by pointer if mutation is needed:
now := time.Now()
later := now.Add(2 * time.Hour)

Q: What is time.Duration?
A: time.Duration is an alias for int64 representing nanoseconds. Constants like time.Second, time.Millisecond, time.Minute, time.Hour are predefined. Arithmetic is intuitive: 30 * time.Second.

Q: How do you format a time.Time?
A: Use the time.Format method with a reference layout "Mon Jan 2 15:04:05 MST 2006" (01/02 03:04:05PM '06):
t.Format("2006-01-02 15:04:05")
For RFC 3339 / ISO 8601 use the constant time.RFC3339.

Q: How do you parse a time string?
A: t, err := time.Parse("2006-01-02", "2026-06-25")
The format string uses the same reference layout as Format. For UTC parsing, use time.Parse(time.RFC3339, s).

Q: What is the difference between time.Now and time.Now in UTC?
A: time.Now() returns local time, which includes the system's time zone.
now.UTC() (or time.Now().UTC()) returns the same instant in UTC. For servers, prefer storing and transmitting UTC, then convert on display.

Q: What is the time.Tick function?
A: time.Tick(d) returns a channel that delivers time.Time values at the specified interval:
for t := range time.Tick(time.Second) { fmt.Println(t) }
Note: it is intended for simple cases; time.NewTicker gives you explicit control to stop.

Q: What is the difference between time.Timer and time.Ticker?
A: A Timer fires once after a duration: timer := time.NewTimer(2 * time.Second).
A Ticker fires repeatedly at an interval: ticker := time.NewTicker(500 * time.Millisecond).
Always call Stop() when no longer needed to free resources.

Q: How does the os package's environment variable API work?
A: os.Getenv("KEY") — read an env var (returns "" if missing).
os.LookupEnv("KEY") — read with presence check: val, ok := os.LookupEnv("KEY").
os.Setenv("KEY", "val") and os.Unsetenv("KEY") modify the process environment.

Q: What is the filepath package used for?
A: path/filepath builds and parses OS-specific paths:
filepath.Join("a", "b", "c.txt") → "a/b/c.txt" on Unix, "a\b\c.txt" on Windows.
filepath.Separator gives the OS separator.
Use path (without filepath) for slash-separated paths used in URLs.

Q: How do you read an entire file in Go?
A: data, err := os.ReadFile("file.txt") — returns []byte and any error.
For streaming, use os.Open then read in chunks.
For line-by-line processing, use bufio.Scanner with scanner.Split(bufio.ScanLines).

Q: How do you write to a file in Go?
A: err := os.WriteFile("file.txt", data, 0644) writes a byte slice in one call.
For more control use os.Create to get a *os.File, then write with the file's Write or WriteString methods. The permission bits (e.g. 0644) are combined with the process umask.

Q: What is the io.Reader and io.Writer interface?
A: io.Reader: Read(p []byte) (n int, err error) — reads into p.
io.Writer: Write(p []byte) (n int, err error) — writes from p.
They are the cornerstone abstractions in Go I/O — files, network connections, buffers, and HTTP bodies all satisfy them.

Q: What is the bufio package?
A: bufio provides buffered I/O wrapping an io.Reader or io.Writer:
r := bufio.NewReader(file) — reads in chunks, reducing syscalls.
w := bufio.NewWriter(file) — buffers writes; call Flush() before closing.
scanner := bufio.NewScanner(file) — convenient line-by-line reading.

Q: What is io.Copy?
A: io.Copy(dst io.Writer, src io.Reader) (written int64, err error) copies from src to dst until EOF or error. It uses an internal 32 KB buffer and is the idiomatic way to stream data between sources.

Q: What is the difference between io.ReadAll and os.ReadFile?
A: os.ReadFile(name) opens the file, reads it fully, and closes it — returns []byte.
io.ReadAll(r) reads fully from any io.Reader — useful for http.Response.Body, strings.Reader, etc. They are otherwise similar in result.

Q: How do you encode a struct to JSON with custom field names?
A: Use struct tags:
type User struct {
  Name string `json:"name"`
  Email string `json:"email,omitempty"`
  Pass string `json:"-"`
}
Tags control JSON keys, omit-on-zero (omitempty), and skip fields (-).

Q: What is the difference between json.Marshal and json.Encoder?
A: json.Marshal(v) returns the []byte representation of v.
json.NewEncoder(w).Encode(v) writes the JSON to an io.Writer directly, appending a newline. Encoders are preferred for streams; marshals for in-memory data.

Q: What is the difference between json.Unmarshal and json.Decoder?
A: json.Unmarshal(data, &v) parses a complete byte slice in one call.
json.NewDecoder(r).Decode(&v) reads from an io.Reader and can process streamed / concatenated JSON objects one at a time.

Q: How do you handle unknown JSON fields in Go?
A: By default, json.Unmarshal silently ignores unknown fields. To make it strict, set a decoder option:
dec := json.NewDecoder(r)
dec.DisallowUnknownFields()
This causes an error if the JSON contains fields not present in the target struct.

Q: What is the encoding/binary package?
A: encoding/binary reads and writes fixed-size binary values to/from byte slices: binary.BigEndian.PutUint32(buf, v), binary.LittleEndian.Uint16(buf). It also defines binary.Read and binary.Write for struct I/O.

Q: What is the encoding/hex package?
A: encoding/hex encodes/decodes to/from hexadecimal:
hex.EncodeToString([]byte{0xde, 0xad}) → "dead"
data, _ := hex.DecodeString("beef")
Useful for hashing output, debugging binary data, and crypto key representation.

Q: What is encoding/base64 used for?
A: encoding/base64 encodes binary data as ASCII text for safe transport in JSON, URLs, or email:
base64.StdEncoding.EncodeToString([]byte("data"))
Variants: StdEncoding, URLEncoding (uses -_), RawStdEncoding / RawURLEncoding (no padding).

Q: How do you start an HTTP server with a custom handler?
A: mux := http.NewServeMux()
mux.HandleFunc("/hello", helloHandler)
http.ListenAndServe(":8080", mux)
Customize the server with &http.Server{Addr: ":8080", Handler: mux, ReadTimeout: 5*time.Second}.

Q: What is an http.HandlerFunc?
A: http.HandlerFunc is a function type that implements http.Handler:
type HandlerFunc func(http.ResponseWriter, *http.Request)
It lets you use plain functions as handlers:
mux.HandleFunc("/", func(w, r) { ... })

Q: What is http.Handler?
A: http.Handler is the interface every HTTP handler must satisfy:
type Handler interface {
  ServerHTTP(http.ResponseWriter, *http.Request)
}
Implement it on a struct to create handlers with state (e.g. dependencies, configuration).

Q: What does http.Error do?
A: http.Error(w, "message", http.StatusBadRequest) writes a plain-text error response and prevents further writes by calling w.Header().Set("Content-Type", "text/plain; charset=utf-8") and http.StatusBadRequest. Common status constants: 200, 404, 500.

Q: How do you set HTTP response headers?
A: w.Header().Set("Content-Type", "application/json")
w.Header().Add("X-Custom", "v1")
Headers must be set before calling w.WriteHeader(code) or any w.Write call. Once the response is started, headers are immutable.

Q: What is the difference between w.Write and w.WriteHeader?
A: w.Write([]byte) writes the response body. If no status has been sent, it implicitly sends 200 OK.
w.WriteHeader(404) sends the status code without a body. Call it before writing the body to set a non-200 status.

Q: How do you make an HTTP request in Go?
A: resp, err := http.Get("https://api.example.com/data")
For POST/PUT etc.:
req, _ := http.NewRequest("POST", url, body)
resp, err := http.DefaultClient.Do(req)
Always defer resp.Body.Close() and read the body to completion.

Q: How do you set a timeout on http.Client?
A: client := &http.Client{Timeout: 10 * time.Second} sets a total timeout for the whole request.
For finer control, use a context.Context:
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
req = req.WithContext(ctx)

Q: What is the difference between http.NewRequest and http.Post?
A: http.Post(url, contentType, body) is a convenience wrapper that builds a POST request internally and uses http.DefaultClient.
http.NewRequest(method, url, body) returns a request you can customize (headers, context) before sending via client.Do(req).

Q: How do you serve static files in Go?
A: mux.Handle("/", http.FileServer(http.Dir("./public")))
or, to strip a path prefix:
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
The http.Dir type implements http.FileSystem.

Q: What are Go interfaces compared to interfaces in Java or C#?
A: Go interfaces are implicitly satisfied — no implements keyword. A struct satisfies an interface as soon as it has all required methods. This enables structural typing and is one of Go's defining features.

Q: What is a method set in Go?
A: The method set of a type is the set of methods defined for it. For value T it includes methods with receiver T. For pointer *T it includes both T and *T receivers. A type satisfies an interface only if all interface methods are in its method set.

Q: What is interface satisfaction at compile time?
A: Use a blank variable assignment to force compile-time check:
var _ io.Reader = (*MyType)(nil)
This fails to compile if *MyType does not satisfy io.Reader. A common idiom in package initialization.

Q: What is the difference between interface{} and any?
A: In Go 1.18+, any is an alias for interface{}. They are exactly the same type — any was introduced for readability. Prefer any in new code.

Q: How do you check whether a value implements an interface at runtime?
A: You usually cannot — Go checks interface satisfaction at compile time. If you need a runtime check, use a type assertion:
if r, ok := val.(io.Reader); ok { ... }

Q: What is a method expression?
A: A method expression binds a method to its receiver type to produce a function value:
f := (*Time).Add has type func(t *Time, d Duration) Time.
This is rare; method values (e.g. t.Add) are far more common.

Q: What is a method value?
A: A method value binds a method to a specific receiver:
t := time.Now()
addHour := t.Add has type func(time.Duration) time.Time — a closure-like form useful for passing to other functions.

Q: What is the variadic function syntax?
A: A variadic function accepts any number of a particular type's arguments using ...:
func sum(nums ...int) int { ... }
Inside the function, nums is a []int. Call with sum(1, 2, 3) or sum(slice...).

Q: What is a higher-order function in Go?
A: A function that takes a function as an argument or returns a function:
func Map[T, U any](s []T, f func(T) U) []U { ... }
Common in the standard library: sort.Slice, http.HandlerFunc, html/template.

Q: What is a function literal in Go?
A: Also called an anonymous function:
add := func(a, b int) int { return a + b }
Commonly used inline with go, defer, and callbacks.

Q: What is the difference between func and method declarations?
A: A function is declared with func name(args) returns at package or block level.
A method adds a receiver: func (r *T) name(args) returns. Methods can only be defined at package level, on named types in the same package.

Q: What is a first-class function?
A: Go functions are first-class values — they can be assigned to variables, passed as arguments, returned from other functions, and stored in maps/slices:
ops := map[string]func(int, int) int{"+": add, "-": sub}

Q: What is the init order in Go packages?
A: Order:
1. Package-level variables are initialized in dependency order
2. Each file's init() functions run in lexical filename order
3. main() runs last (only in package main)
Multiple init functions in one file run in declaration order.

Q: What is the underscore import in Go?
A: import _ "database/sql/driver/mysql" imports a package solely for its side effects (e.g. registering a database driver). The package's exported identifiers are not accessible — only its init runs.

Q: What is a dot import?
A: import . "math" brings exported names into the current namespace so they can be used without a prefix: Pi instead of math.Pi. Avoid in production code — it hurts readability and risks collisions.

Q: What is an aliased import?
A: import f "fmt" renames an import locally. Useful when two packages share a name, or to shorten long names in test files:
import j "encoding/json"

Q: What is a Go build constraint / build tag?
A: Special comments near the top of a file that limit which platforms the file is included in:
//go:build linux && amd64
// +build linux,amd64 (old syntax)
Constraints are evaluated by go build automatically.

Q: What are OS- and architecture-specific file names?
A: Go automatically includes files whose names end with _GOOS or _GOARCH for the current platform:
net_linux.go (Linux only)
asm_amd64.s (amd64 assembly)
Useful for platform-specific implementations.

Q: What is a goroutine stack growth?
A: Each goroutine starts with a small stack (~2 KB) and grows dynamically as needed. The runtime copies the stack to a larger region and updates pointers. Costly but amortized — well-behaved programs hit the growth rarely.

Q: What is goroutine scheduling latency?
A: Go 1.14 introduced asynchronous preemption: long-running goroutines are forcefully preempted at function call safe points, not just at function returns. This eliminated scheduler starvation when one goroutine ran a tight loop without function calls.

Q: What is the Go memory model?
A: Documented in sync/atomic and the Go memory model spec, it defines when writes in one goroutine are guaranteed to be visible to reads in another. Synchronization primitives (channels, mutexes, atomics) establish happens-before relationships; nothing else does.

Q: What is a happens-before relationship?
A: Two operations have a happens-before relationship if Go's memory model guarantees the second sees the first's effects. Channel sends happen before the corresponding receive completes; Unlock happens before the next Lock. Without such a relationship, behavior is undefined.

Q: What is the difference between unbuffered channel send and receive timing?
A: For an unbuffered channel ch:
- ch <- v blocks until a receiver is ready
- v := <-ch blocks until a value is sent
Both complete at the same instant, providing a synchronization point between goroutines.

Q: What is a directional channel?
A: Channels can be used as send-only or receive-only:
var sendOnly chan<- int = ch
var recvOnly <-chan int = ch
Common for function parameters to restrict capabilities and document intent:
func produce(out chan<- int)

Q: How do you select on a closed channel?
A: Reading from a closed channel returns the zero value immediately without blocking. In a select, a case on a closed channel is therefore always ready — easy to accidentally spin. for range ch terminates naturally when the channel is closed and drained.

Q: What is the difference between nil and closed channels?
A: A nil channel blocks forever: <-nil never completes.
A closed channel returns immediately: <-closed yields the zero value and ok=false.
This difference enables idioms like disabling a select case by assigning nil.

Q: What is a worker pool in Go?
A: A pattern using a fixed number of goroutines reading jobs from a shared channel:
jobs := make(chan Job, 100)
for w := 0; w < numWorkers; w++ { go worker(jobs) }
Bounds concurrency, reduces goroutine creation overhead, and is the standard way to throttle parallel work.

Q: What is the errgroup package?
A: golang.org/x/sync/errgroup coordinates a group of goroutines that all share a single error and a context:
g, ctx := errgroup.WithContext(ctx)
g.Go(func() error { ... })
err := g.Wait()
The first non-nil error cancels the shared context.

Q: What is a pipeline pattern in Go?
A: A pipeline chains stages, each consuming from an input channel and producing to an output:
gen → square → filter → sink
Each stage runs in its own goroutine, processing one element at a time. Use for range + close at each stage to propagate termination.

Q: What is the sema package used for?
A: golang.org/x/sync/semaphore limits concurrency to N using a weighted semaphore:
sem := semaphore.NewWeighted(10)
sem.Acquire(ctx, 1)
Useful when you have many tasks but want to bound parallel resource use (e.g. DB connections, file handles).

Q: What is a singleflight in Go?
A: golang.org/x/sync/singleflight collapses multiple concurrent calls for the same key into a single function call — useful for cache stampede prevention:
v, err, shared := sf.Do("key", func() (any, error) { return expensive() })

Q: What is the difference between a string and a []byte in Go?
A: Strings are immutable, read-only byte sequences. []byte is a mutable slice. Converting between them allocates and copies (in most Go versions). Use []byte for I/O buffers; use string for immutable text.

Q: What is a map iteration order?
A: Map iteration order in Go is intentionally randomized (since Go 1.0). Each for k, v := range m returns keys in a different order. Do not rely on iteration order; sort keys if you need deterministic output.

Q: What is the difference between nil interface and typed-nil interface?
A: A nil interface is zero-valued: var i io.Reader is nil.
A typed nil holds a non-nil pointer to a nil struct: var p *MyType = nil; var i io.Reader = p — i != nil! This is a famous Go gotcha; check if p == nil explicitly.

Q: What is an unsafe.Pointer?
A: unsafe.Pointer is a generic pointer type that bypasses Go's type system:
p := unsafe.Pointer(&x)
It can be converted to other pointer types or to uintptr. Using it is dangerous; only for low-level code like C interop or performance-critical hot paths.

Q: What is the uintptr type?
A: uintptr is an unsigned integer large enough to hold a pointer bit pattern. It is not a pointer — the GC does not track it. Used with unsafe.Pointer for pointer arithmetic; almost never needed in application code.

Q: What is cgo?
A: cgo lets Go call C code. Add a special comment:
// #include <stdio.h>
import "C"
Then call C functions through the C package. cgo has overhead, complicates builds, and disables some Go tooling — use sparingly.

Q: What is a build cache?
A: Go caches build artifacts in $GOCACHE/build (default ~/.cache/go-build). Identical compilations reuse cached results, making go build and go test fast. Clear with go clean -cache.

Q: What is the difference between go install and go build?
A: go build compiles packages and discards the binary (or produces one in the current directory for main).
go install compiles and places the binary in $GOPATH/bin. Use install to make CLI tools available on your PATH.

Q: What is the -trimpath flag?
A: go build -trimpath removes all file system paths from the binary, replacing them with module paths. This makes builds reproducible across machines and avoids leaking local directory structure. Recommended for production builds.

Q: What is the embed package?
A: Introduced in Go 1.16, embed lets you embed files into the binary:
import _ "embed"
//go:embed hello.txt
var s string
Files become variables. Useful for shipping templates, configs, and static assets with no runtime file dependency.

Q: What is go.sum?
A: go.sum is a file in a Go module that contains cryptographic checksums of the exact module versions used (and their transitive dependencies). go mod verify checks them. Commit both go.mod and go.sum to version control.

Q: What is the difference between go get and go install?
A: go get adds a dependency to go.mod and downloads it. It does not produce an executable.
go install compiles and installs a binary. Since Go 1.18, go install pkg@version can install CLI tools from a module path.

Q: What is the GOPATH?
A: GOPATH is the legacy Go workspace location where dependencies and binaries lived before modules. With modules it is mostly irrelevant, but it still controls where go install puts binaries: typically ~/go by default.

Q: What is the difference between go.mod's require direct and indirect?
A: // require lists dependencies your code directly imports.
// indirect marks dependencies pulled in by your dependencies (transitive).
Go's tooling moves entries between these automatically as you run go mod tidy.

Q: What is a replace directive in go.mod?
A: replace github.com/old/pkg => ../local/pkg overrides where a module is loaded from. Useful for:
- Local development of dependent modules
- Forking an external library
- Working around broken versions
Do not commit replace directives to shared modules.

Q: What is a retract directive?
A: Introduced in Go 1.16, retract in go.mod marks a version as unsafe to use:
retract v1.2.3 // security issue, use v1.2.4
Anyone running go list -m -u all sees a warning.

Q: What is a go workspace (go.work)?
A: Introduced in Go 1.18, a go.work file lists multiple modules to work on together:
go 1.22
use ./modA
use ./modB
Useful for multi-module development without replacing directives.

Q: What is go mod tidy?
A: go mod tidy synchronizes go.mod and go.sum with the actual imports in the code. It adds missing dependencies, removes unused ones, and downloads checksums. Run after adding or removing imports.

Q: What is go mod vendor?
A: go mod vendor copies all dependencies into a vendor/ directory. Builds then use those vendored copies, ignoring the module cache. Useful for air-gapped or reproducible builds. Pass -mod=vendor to go build to use them.

Q: How do you write a benchmark in Go?
A: Add a function func BenchmarkX(b *testing.B) in a _test.go file:
for i := 0; i < b.N; i++ { work() }
Run with go test -bench=.. The framework adjusts b.N until the result is statistically meaningful.

Q: What is b.ResetTimer used for?
A: b.ResetTimer() discards time accumulated during expensive setup so the benchmark measures only the hot path. Always call it after any setup that should not count toward the result.

Q: What is b.RunParallel used for?
A: b.RunParallel(func(pb *testing.PB) { for pb.Next() { work() } }) runs the benchmark across GOMAXPROCS goroutines to measure parallel performance. Use -cpu flag to control the parallelism level.

Q: What is the testing.TB interface?
A: testing.TB is the shared interface of *testing.T and *testing.B — exposes Log, Logf, Error, Fatal, Skip, Helper, Cleanup. Useful when writing helpers that work in both tests and benchmarks.

Q: What is t.Helper used for?
A: t.Helper() marks a function as a test helper: failure messages report the caller's line number, not the helper's. Always call it in helpers like assertEqual to make test failures easier to read.

Q: What is t.Cleanup?
A: t.Cleanup(func()) registers a function to run after the test (or subtest) finishes. Similar to defer but scoped to the test, including all subtests. Useful for releasing resources shared across subtests.