5. Standard Library
Everyday batteries: time, strings/bytes, files/JSON, HTTP servers/clients, and paths.
Question: How do you correctly format a date and time in Go, and why is the layout string unusual?
Answer: You use the time.Format
method with a specific reference layout string: Mon Jan 2 15:04:05 MST 2006
. This layout tells the Format
function how to format the time by providing an example of the desired output.
Explanation: Unlike other languages that use abstract placeholders (YYYY-MM-DD
), Go uses this specific reference time as a mnemonic. The components correspond to Month Day Hour Minute Second Timezone Year
. You arrange these components in the format you want. For example, to get 2006-01-02
, you would use the layout string "2006-01-02"
.
now := time.Now()
fmt.Println(now.Format("2006-01-02")) // ISO-like date
fmt.Println(now.Format(time.RFC3339)) // 2006-01-02T15:04:05Z07:00
Question: What are some common and useful functions in the
strings
package?
Answer: The strings
package provides many essential functions for string manipulation, including strings.TrimSpace
to remove whitespace, strings.Split
to divide a string into a slice, strings.Join
to concatenate a slice into a single string, strings.ReplaceAll
for search-and-replace, and strings.HasPrefix
/strings.HasSuffix
to check for substrings at the beginning or end of a string.
Explanation: Becoming familiar with the strings
and bytes
packages is crucial for a Go developer. They provide optimized and convenient routines that prevent you from reinventing the wheel for common text processing tasks.
Question: How do you read the contents of a file?
Answer: For simple cases where you need the entire file content at once, use os.ReadFile
. For larger files or when you need to process a file line-by-line, a more memory-efficient approach is to use os.Open
combined with a bufio.NewScanner
.
Explanation: os.ReadFile
is convenient but can consume a lot of memory if the file is very large. The bufio.Scanner
approach is more robust as it reads the file in chunks, making it suitable for streaming data and handling large files without running out of memory.
Question: How do you marshal and unmarshal JSON using struct tags?
Answer: Use the encoding/json
package. Fields must be exported to be marshaled. Tags control names and omission.
Explanation: Tags like json:"name,omitempty"
rename fields and omit zero values. Unexported (lowercase) fields are ignored. nil
slices marshal to null
, empty slices to []
.
type User struct {
ID int `json:"id"`
Name string `json:"name,omitempty"`
}
b, _ := json.Marshal(User{ID: 1})
var u User
_ = json.Unmarshal(b, &u)
Question: How do you start a simple HTTP server?
Answer: Use net/http
with a handler and http.ListenAndServe
.
Explanation: Handlers take (w http.ResponseWriter, r *http.Request)
. For graceful shutdown, use http.Server
with a context.
http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("pong"))
})
log.Fatal(http.ListenAndServe(":8080", nil))
Question: How do you gracefully shut down an HTTP server?
Answer: Use http.Server
and call Shutdown(ctx)
on signal. This drains existing connections.
Explanation: Combine with context.WithTimeout
and OS signal handling.
srv := &http.Server{Addr: ":8080"}
go func() { _ = srv.ListenAndServe() }()
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt)
<-sig
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_ = srv.Shutdown(ctx)
Question: When to use
path/filepath
vspath
?
Answer: Use path/filepath
for OS-native filesystem paths; use path
for slash-separated (URL-like) paths.
Question: How do you use the new structured logger
log/slog
(Go 1.21+)?
Answer: Create a logger with a handler and log key-value pairs.
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
logger.Info("started", "version", "1.0.0")
Question: How do you set timeouts and connection limits for HTTP clients?
Answer: Set http.Client{Timeout: ...}
and customize http.Transport
for pools and per-dial timeouts.
Explanation: Reasonable defaults prevent hangs and manage resources.
client := &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
}
Question: How do you read environment variables safely?
Answer: Use os.LookupEnv
to distinguish unset from empty values.
Explanation: os.Getenv
returns an empty string for both unset and empty; LookupEnv
returns (value, found)
.
Question: How do you parse command-line flags?
Answer: Use the flag
package to declare and parse flags in main()
.
Explanation: Define flags as pointers and call flag.Parse()
.
port := flag.Int("port", 8080, "listen port")
flag.Parse()
log.Printf("listening on :%d", *port)