Irbisa · Cheatsheet

Standard Library in Practice

io and bufio, encoding/json, time, strconv, regexp, embed

Middle Developer · 23 questions

  1. 01

    Which struct fields does encoding/json encode, and what can a json:"..." tag change about them?

    encoding/json only sees exported fields: the ones whose name starts with a capital letter.

    // wrong: nothing is exported: Marshal returns "{}" and a nil errortype order struct {	id     int64	total  int64 `json:"total"` // a tag on an unexported field does nothing	status string}…
  2. 02

    How do you read a file in Go (os.ReadFile, os.Open with bufio, or io.Copy), and when do you pick each?

    os.ReadFile loads a whole file into memory in one call and suits small files such as configs.

    // small file: one call, memory = file sizefunc loadJSON(path string, v any) error {	b, err := os.ReadFile(path)	if err != nil {		return err	}…
  3. 03

    What does a bufio.Writer do with the bytes you write into it, and why must you call Flush before closing the file?

    bufio.Writer keeps your output in an in-memory buffer (4 KB by default) and writes to the underlying file only when the buffer fills or when you call Flush.

    type Row struct {	ID   int64	Name string} func export(path string, rows []Row) (err error) {…
  4. 04

    What does this print, and what is the right way to turn a number into a string and back?

    func main() {	n := 65	a := string(n)	b := strconv.Itoa(n)	c, err := strconv.Atoi("65 ")	fmt.Printf("%q %q %d %v\n", a, b, c, err)}

    It prints "A" "65" 0 strconv.Atoi: parsing "65 ": invalid syntax.

  5. 05

    Why does Go format dates with the layout 2006-01-02 15:04:05 instead of YYYY-MM-DD?

    A Go layout is an example of one reference time, Mon Jan 2 15:04:05 MST 2006, written the way you want the output to look.

    const layout = "2006-01-02 15:04:05" // an example, not a pattern func main() {	t := time.Date(2024, 3, 5, 9, 7, 0, 0, time.UTC) 	// wrong: Format never errors: unknown letters are copied through as themselves…
  6. 06

    What does //go:embed do, which variable types can it fill, and why does it fix a file path that works from the project directory but fails on the server?

    //go:embed copies files from the package directory into the binary at build time: into a string, a []byte or an embed.FS.

    //go:embed version.txtvar version string // one file as a string //go:embed templates/*.htmlvar tmplFS embed.FS…
  7. 07

    When do you use crypto/rand instead of math/rand, and what changed with math/rand/v2 and seeding?

    crypto/rand is for anything an attacker must not guess: tokens, session ids, keys, reset links.

    import (	crand "crypto/rand"	"math/rand/v2"	"time")…
  8. 08

    How would you gzip, hash and count a file while uploading it (in one pass, without holding it in memory) using only the standard library?

    Every streaming type in the standard library speaks the same two one-method interfaces, io.Reader and io.Writer, so compression, hashing and counting are wrappers you stack on each other, and io.Copy drives the whole chain.

    // One pass: gzip to dst, sha256 of the plaintext, count of compressed bytes.func upload(dst io.Writer, name string) (sum []byte, n int64, err error) {	f, err := os.Open(name)	if err != nil {		return nil, 0, err	}…
  9. 09

    What is the difference between bufio.Scanner and bufio.Reader, and why does a Scanner stop on some files with token too long?

    bufio.Scanner is a convenient tokenizer (a line or a word per Scan()), but it refuses any token over 64 KB (bufio.MaxScanTokenSize).

    func importLines(r io.Reader, handle func([]byte) error) error {	s := bufio.NewScanner(r)	s.Buffer(make([]byte, 0, 64*1024), 4*1024*1024) // 64 KB start, 4 MB cap	for s.Scan() {		// s.Bytes() aliases the scanner's buffer: copy it if you keep it		if err := handle(s.Bytes()); err != nil {…
  10. 10

    What does omitempty treat as empty, and why is a zero time.Time still encoded?

    omitempty skips only false, 0, "", nil pointers and interfaces, and zero-length slices, maps and arrays; a struct is never empty to it, so a zero time.Time goes out as "0001-01-01T00:00:00Z".

    type Profile struct {	Tags    []string  `json:"tags"`              // nil -> null, []string{} -> []	Nick    string    `json:"nick,omitempty"`    // "" -> key absent	Score   int       `json:"score,omitempty"`   // 0 -> absent: "score 0" cannot be sent	Seen    *int      `json:"seen,omitempty"`    // nil -> absent, &0 -> "seen":0	Created time.Time `json:"created,omitempty"` // wrong: a struct is never "empty"…
  11. 11

    A webhook relay decodes payloads into map[string]any and re-encodes them. What does this print, and why do large ids come out changed?

    const raw = `{"order_id":12345678901234567}` func main() {	var m map[string]any	json.Unmarshal([]byte(raw), &m)	fmt.Printf("%T\n", m["order_id"]) 	out, _ := json.Marshal(m)	fmt.Println(string(out))}

    It prints float64, then {"order_id":12345678901234568} (one off).

  12. 12

    Config key max_conns became maxConnections and the service booted silently with a zero pool. Which encoding/json rules allowed it, and how do you make it fail?

    Unknown keys are silently discarded, so the renamed key vanished and MaxConns kept its zero value; known keys are also matched case-insensitively, which hides other typos.

    type Config struct {	Addr     string `json:"addr"`	MaxConns int    `json:"max_conns"`} func load(r io.Reader) (Config, error) {…
  13. 13

    Find the bug: some orders get a coupon the customer never entered.

    type Order struct {	ID     string `json:"id"`	Coupon string `json:"coupon"`} func parseOrders(lines [][]byte) ([]Order, error) {	var out []Order	var o Order	for _, line := range lines {		if err := json.Unmarshal(line, &o); err != nil {			return nil, err		}		out = append(out, o)	}	return out, nil}

    o is declared once, outside the loop, and json.Unmarshal sets only the fields present in the input.

  14. 14

    This MarshalJSON should encode Event.At as a plain date. Why does the first call crash the whole process, and what is the fix?

    type Event struct {	Name string    `json:"name"`	At   time.Time `json:"at"`} func (e Event) MarshalJSON() ([]byte, error) {	type payload = Event // "a copy of Event without the method"	return json.Marshal(struct {		payload		At string `json:"at"`	}{payload(e), e.At.Format(time.DateOnly)})}

    json.Marshal checks whether a type implements json.Marshaler before it looks at fields.

  15. 15

    What does the experimental encoding/json/v2 from Go 1.25 change compared with encoding/json, and when do teams still pick easyjson or sonic?

    encoding/json/v2 arrived in Go 1.25 as an experiment behind GOEXPERIMENT=jsonv2: a rewrite with strict defaults and fast decoding.

  16. 16

    What is reflection in Go, where does the standard library rely on it, and what does it cost you?

    Package reflect lets code inspect and change values whose type is known only at run time: their kind, fields, struct tags and methods.

    type Config struct {	Host string `env:"APP_HOST"`	Port int    `env:"APP_PORT"`} // Fills string and int fields from the env vars named in `env` tags.…
  17. 17

    Why is Go's regexp guaranteed to run in linear time, and what can it not do?

    Go's regexp implements RE2: it matches with automata instead of backtracking, so time is linear in the input and no pattern or string can trigger catastrophic backtracking (ReDoS).

  18. 18

    How do you load configuration in a Go service with only the standard library (defaults, environment variables, flags), and where does validation belong?

    Start from a struct of defaults, let environment variables override them and command-line flags override both, then validate the finished struct once at start-up and refuse to boot if anything is wrong.

    type Config struct {	Addr        string	DatabaseURL string	Timeout     time.Duration}…
  19. 19

    How do you write a TCP server with net.Listen and Accept, and what must you add for deadlines and graceful shutdown?

    net.Listen("tcp", addr) returns a listener; a loop calls Accept and hands each net.Conn to its own goroutine.

    type Server struct {	ln    net.Listener	wg    sync.WaitGroup	conns sync.Map      // live connections	done  chan struct{} // closed by Shutdown: the quit signal}…
  20. 20

    NTP steps the clock back 400 ms: time.Since(start) stays right, end.UnixNano() - start.UnixNano() goes negative. What does time.Time carry that explains it?

    A time.Time from time.Now() carries two clocks: a wall-clock reading and a monotonic one.

  21. 21

    How do you ingest a 40 GB NDJSON file whose data shape depends on each line's type, in constant memory and decoding each line into Go values once?

    One json.Decoder over the reader decodes one value at a time in constant memory, and a json.RawMessage field parks the data bytes undecoded until type says which struct they belong in, so each line is decoded into Go values once.

    type Envelope struct {	Type string          `json:"type"`	Data json.RawMessage `json:"data"` // raw bytes until Type is known} type Push struct{ Ref string `json:"ref"` }…
  22. 22

    What can unsafe.Pointer do that ordinary Go cannot, and why is a zero-copy []byte-to-string conversion with unsafe.String a bug if the bytes change?

    unsafe.Pointer converts to and from any pointer type and uintptr, letting code reinterpret memory and do pointer arithmetic outside the type system.

    func main() {	buf := []byte("alice") 	// wrong: zero-copy, so name shares buf's bytes	name := unsafe.String(unsafe.SliceData(buf), len(buf))	seen := map[string]bool{name: true}…
  23. 23

    Find the bug: checksum of a gzip.Reader usually does not match sha256sum of the unpacked file, yet it returns no error.

    // called as: zr, _ := gzip.NewReader(f); sum, err := checksum(zr)func checksum(r io.Reader) ([]byte, error) {	h := sha256.New()	buf := make([]byte, 32*1024)	for {		n, err := r.Read(buf)		if err == io.EOF {			break		}		if err != nil {			return nil, err		}		h.Write(buf[:n])	}	return h.Sum(nil), nil}

    The loop checks err before it uses n.