Text, Time and Collections
The standard library packages you touch every day for text, time and collections, where the idiomatic call and its allocation behaviour matter more than the API list.
part ofGo (Golang)overview, primer and where to startread it →on this pageshowhide
explore
- String and Byte Handling18 questions
- Searching, Splitting and Joining4 questions
- Trimming, Replacing and Casing4 questions
- strings.Builder and bytes.Buffer5 questions
- UTF-8 Decoding and Runes5 questions
- Formatting and Parsing18 questions
- Float Precision and Round-Tripping5 questions
- fmt Verbs and Stringer5 questions
- strconv Conversions and Errors4 questions
- Allocation in fmt Calls4 questions
- Regular Expressions13 questions
- RE2 Semantics and Limits5 questions
- Compiling and Reusing Patterns4 questions
- Submatches and Replacement4 questions
- Template Rendering19 questions
- Actions, Pipelines and Data5 questions
- Named Blocks and ParseFS5 questions
- FuncMap Helpers and Errors4 questions
- Contextual Escaping in Output5 questions
- Instants, Durations and Clocks17 questions
- Calendar and Elapsed Arithmetic4 questions
- Monotonic and Wall Readings4 questions
- Reference Layouts and Parsing5 questions
- Zones and tzdata Loading4 questions
- Slices, Maps and Ordering27 questions
- container/heap Priority Queues4 questions
- sort.Interface and Custom Orders5 questions
- Cloning and Equality Checks4 questions
- slices.Sort and BinarySearch5 questions
- cmp.Ordered and Compare5 questions
- Deterministic Map Order4 questions
- Lazy Sequences17 questions
- iter.Seq and iter.Seq24 questions
- Writing Push Iterators5 questions
- Pull Iterators and Cleanup4 questions
- Collecting and Emitting Sequences4 questions
questions
129 · 7 sectionsWhy is strings.Builder preferred over `+=` when assembling a string in a Go loop?
basics
~20 sGo strings are immutable, so each += builds a brand-new string and copies everything accumulated so far. strings.Builder appends into one growable byte slice instead, and its String method hands those bytes over as a string without a final copy.
What is the difference between strings.Split(s, " ") and strings.Fields(s) when splitting a line into words?
basics
~20 sstrings.Split cuts at every single separator, so a run of two spaces produces an empty string between them. strings.Fields treats any run of one or more Unicode whitespace characters as one separator and never returns an empty element.
In Go, how does strings.Trim's cutset differ from strings.TrimPrefix's prefix?
basics
~20 sstrings.Trim takes a cutset: a set of individual characters, stripped repeatedly from both ends in any order. strings.TrimPrefix takes a literal string and removes it once from the front, returning the input unchanged when that prefix is absent.
Which Go standard library call counts the runes in a string, and why can its result surprise a user?
basics
~20 sutf8.RuneCountInString from the unicode/utf8 package returns the number of Unicode code points in a Go string. It can still surprise: accented letters, emoji and flags are often several code points that a user sees as one character.
When would you reach for bytes.Buffer instead of strings.Builder in Go?
basics
~20 sReach for bytes.Buffer when you need to read the accumulated bytes back, hand them to something expecting an io.Reader, or keep the capacity across a Reset. Use strings.Builder when the result is a string: its String method avoids the final copy.
In Go's fmt, how do the %f, %e and %g verbs differ when printing a float64?
basics
~20 s%f prints decimal digits with no exponent, %e prints scientific notation, and %g picks between them by magnitude. %f and %e default to six digits after the point; %g defaults to the shortest digits that identify the value uniquely.
What does strconv.Atoi return when the input string is not a valid integer?
basics
~20 sstrconv.Atoi returns two values, the parsed int and an error. On bad input it returns 0 plus a non-nil error rather than panicking, so the 0 is meaningless until you have checked that the error is nil.
In Go, how do the fmt verbs %v, %+v and %#v differ when printing a struct?
basics
~10 s%v prints only a struct's field values, like {s-42 <nil>}. %+v adds the field names. %#v prints a Go-syntax literal with the package-qualified type name and quoted strings, like main.Session{ID:"s-42"}.
Why does strconv.FormatFloat with precision -1 round-trip exactly through ParseFloat?
basics
~20 sPrecision -1 makes strconv.FormatFloat emit the fewest digits that no other float64 shares, so strconv.ParseFloat reads the string back as the identical value. Any fixed precision can print a string that parses back as a different number.
When does fmt call a type's String() method, and why can a pointer receiver hide it?
basics
~20 sfmt calls String() when the operand satisfies fmt.Stringer and the verb is %v, %s, %q, %x or %X. If String has a pointer receiver, only *T satisfies the interface, so printing a T value falls back to default formatting.
In Go's regexp package, when should you use regexp.MustCompile instead of regexp.Compile?
basics
~20 sregexp.MustCompile panics if the pattern is invalid and returns only a *regexp.Regexp, so it suits patterns written as literals in your source, normally as a package-level var. Use regexp.Compile, which returns an error, for any pattern supplied at runtime.
Why does Go's regexp package reject lookaheads and backreferences?
basics
~20 sGo's regexp implements RE2 semantics: it simulates an automaton over the input instead of backtracking, so matching time stays bounded by input length times pattern size. Lookaheads and backreferences cannot be expressed in that model, so such patterns fail to compile.
In Go's regexp package, what does FindStringSubmatch return for a match and for a non-match?
basics
~20 sFindStringSubmatch returns a []string in which element 0 is the entire matched text and elements 1..n are the capture groups, numbered by opening parenthesis. If the pattern matches nowhere in the input it returns nil, so check for nil before indexing.
Why is regexp.MatchString(pattern, s) more expensive than calling MatchString on a compiled *regexp.Regexp?
basics
~20 sThe package-level regexp.MatchString compiles its pattern from scratch on every call and throws the compiled matcher away afterwards. The method runs on a *regexp.Regexp that was compiled once, so each call pays only for matching.
In Go's regexp package, how do you turn on case-insensitive or dot-matches-newline matching?
basics
~20 sPut the flag inside the pattern text: (?i) for case-insensitive, (?s) to let . match a newline. Go's regexp has no flags argument, so (?i), (?m), (?s) and (?U) written in the pattern are the only way to set modes.
In a Go text/template, what does {{.Name}} resolve against, and how do Parse and Execute fit together?
basics
~20 sDot is the current data value, so {{.Name}} reads a Name field, map key or method from it. Parse compiles the template text once; Execute applies it to one data value and writes the output.
In Go's html/template, what do the {{define}} and {{template}} actions do, and when do you need ExecuteTemplate rather than Execute?
basics
~20 s{{define "name"}}...{{end}} names a template inside the parsed text; {{template "name" .}} renders it in place with the data you give it. Execute runs the receiver template; ExecuteTemplate picks one associated template from the set by name.
What does html/template escape automatically that text/template leaves untouched?
basics
~20 shtml/template escapes every value it substitutes, choosing the escaping from where the value lands in the page: HTML text, an attribute, a script block or a URL. text/template escapes nothing and writes the value as-is.
Why must a Go template's Funcs call come before Parse when the template calls a custom function?
basics
~20 sParsing resolves every function name against the template's func map. Register the helper after Parse and the parser has never heard of it, so Parse fails with a "function not defined" error instead of failing later at Execute.
Inside {{range .Items}} in a Go template, what happens to dot, and how do you reach the top-level value?
basics
~20 sInside a range body dot is rebound to the current element, so outer fields are unreachable through it. Use $, which stays bound to the value passed to Execute, or capture what you need in a variable before the loop.
Why does Go's time formatting use the layout string "2006-01-02" instead of a pattern like "yyyy-MM-dd"?
basics
~20 sGo has no pattern letters. A layout is one fixed reference instant, Mon Jan 2 15:04:05 MST 2006, written in the shape you want output. So 2006 means year, 01 month, 02 day, 15 hour, 04 minute, 05 second.
What two clock readings does Go's time.Now() put into one time.Time, and which one does time.Since use?
basics
~20 stime.Now() returns a time.Time holding both a wall-clock reading, which tells the calendar date and time and can be stepped by the system, and a monotonic reading, which only moves forward. time.Since subtracts using the monotonic reading.
In Go, what is a time.Duration and how do you express a three-second value?
basics
~20 sA time.Duration is an int64 count of nanoseconds, not a struct, so durations are plain numbers you can add, subtract and compare. Write three seconds as 3 * time.Second, multiplying by one of the time package's unit constants.
What do time.UTC, time.Local and t.In(loc) mean for a Go time.Time value?
basics
~20 sA time.Time carries an instant plus a pointer to a time.Location that decides how its calendar fields print. time.UTC and time.Local are two such locations, and t.In(loc) returns the same instant displayed in loc, not a different point in time.
What zone does time.Parse assign when the input carries no offset, and how does time.ParseInLocation differ?
basics
~20 stime.Parse returns a time in UTC whenever the value carries no zone offset or abbreviation, so a local wall-clock string is silently read as UTC. time.ParseInLocation reads the same digits as wall-clock time in a *time.Location you supply.
What does Go's cmp.Compare return, and which types can you call it on?
basics
~10 scmp.Compare returns -1 if the first argument is less, 0 if they are equal, and +1 if it is greater. It accepts any cmp.Ordered type: integers, floats, strings, and named types built on them.
In Go's container/heap, which five methods must your type implement?
basics
~20 scontainer/heap.Interface embeds sort.Interface, so your type needs Len, Less and Swap, plus Push(x any) to append one element and Pop() any to remove and return the last one. Five methods, and you own the storage.
Why does ranging over a Go map yield a different order each run, and how do you produce stable output?
basics
~10 sGo deliberately randomises map iteration, so no order is guaranteed or repeatable. For stable output, copy the keys into a slice, sort that slice, then read the map in that key order.
What does slices.Clone(s) copy that the plain assignment b := s does not?
basics
~10 sslices.Clone allocates a new backing array and copies the elements into it, so the two slices no longer share storage. Plain assignment copies only the slice header, leaving both names pointing at one array.
What does slices.Sort do to a slice, and which element types can it sort?
basics
~20 sslices.Sort reorders a slice in place into ascending order and returns nothing. It is generic over element types that support the less-than operator - integers, floats and strings - so no comparison callback or interface implementation is needed.
In Go's `maps` package, what does `maps.Keys(m)` return, and how do you turn it into a slice?
basics
~10 smaps.Keys returns an iterator of type iter.Seq[K], not a slice. You can range over it directly, or convert it with slices.Collect(maps.Keys(m)) to get a []K. slices.Sorted(maps.Keys(m)) collects and sorts in one call.
What does iter.Pull return, and why use it instead of ranging over an iter.Seq?
basics
~20 siter.Pull(seq) returns two functions: next, which gives the next value plus a bool that is false once the sequence is exhausted, and stop, which ends it early. It turns a sequence into a cursor you advance yourself.
How do you write a Go function returning iter.Seq[string] that a caller can use in a for-range loop?
basics
~20 sReturn a closure whose type is func(yield func(string) bool). Inside it, call yield once per element and stop the moment yield returns false. Ranging over the returned function makes the compiler supply yield from the loop body.
What is Go's `iter.Seq[V]` type, and what does a value of that type actually hold?
basics
~20 siter.Seq[V] is a function type: func(yield func(V) bool). An iterator is just a function that calls yield once per element, and each yield call becomes one iteration of the for range loop that consumes it.
In an iter.Seq iterator you wrote, what must happen when the yield callback returns false, and what if it keeps going?
basics
~20 sA false result from yield means the consuming loop has stopped. The iterator must produce no further values and return promptly, running its deferred cleanup. Calling yield again after it returned false is a run-time panic.