Go Module 4
Arrays, slices, maps and strings interview questions
Interview questions on arrays, slices, maps and strings: warm-ups, then what each harder question tests and how a good answer starts.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
What happens when you assign one array variable to another in Go?
Answered in the lesson Arrays are values: length, copies, comparison
-
Fresher
What does a slice value hold?
Answered in the lesson Slices: length, capacity, append and aliasing
-
Fresher
Why does slices.Sort put "Zoya" before "arjun"?
Answered in the lesson The slices package: sort, search and compare
-
Fresher
How do you tell a missing key from a key that holds the zero value?
Answered in the lesson Maps: lookups, sets, iteration and gotchas
-
Fresher
Why is len("héllo") 6 in Go?
Answered in the lesson Strings, bytes and runes: UTF-8 done right
-
Fresher
What does strconv.Atoi return for "42x"?
Answered in the lesson Numbers as text: strconv, bases and grouping
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Fresher to mid
A function func applyGrace(marks [5]int) adds 5 to every mark below 40, but the report printed after the call still shows the old marks. Explain what happened, then give two fixes and say when you would choose each.
- What it tests
- Knowing that an array parameter is a copy, fixing it with a returned array or a pointer, and choosing between them and a slice by size and intent.
- First step
- Say what the call passes: marks is an array, so applyGrace receives its own copy of all five marks, changes that copy and drops it when it returns. Then choose how the change reaches the caller: return the new array and assign it, or take a pointer, *[5]int, and write through it.
- Follow-ups
-
- Why does the compiler not complain?
- What changes if the parameter is a slice, []int?
- What does each fix cost for a [5]int, and for a [86400]float64?
From the lesson Arrays are values: length, copies, comparison
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A service must find duplicate uploads among 50,000 files by their SHA-256 hashes. Why can the [32]byte that sha256.Sum256 returns be a map key when a []byte cannot, and how do you design the lookup?
- What it tests
- Knowing which types are comparable and why map keys need them, using fixed-size arrays as keys, hashing large files without loading them, and estimating the memory of the index.
- First step
- Start from the rule: a map lookup compares keys with ==, so the key type must be comparable. An array of bytes is comparable element by element, and a slice is not comparable at all. Keep the [32]byte as it is and use map[[32]byte]string, from each hash to the first file that had it.
- Follow-ups
-
- How much memory do 50,000 keys take?
- Why not turn each hash into a hex string first?
- What if two different files had the same hash?
From the lesson Arrays are values: length, copies, comparison
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A service reads 64 MiB log files whole, keeps the first 32 bytes of each as its header in a map and drops the rest. After 100 files the heap holds over 6 GiB. Explain why, say how you would confirm it, and fix it.
- What it tests
- Knowing that a slice keeps its whole backing array alive, confirming it with a heap measurement or profile, and copying out, or reading, only what is kept.
- First step
- Follow what the map holds: each header is data[:32], a slice whose pointer points into the 64 MiB array of its file. While the map holds the slice, the collector must keep that whole array, so 100 headers keep 100 × 64 MiB, 6,400 MiB in all.
- Follow-ups
-
- How do you confirm it before changing any code?
- Does a full slice expression, data[:32:32], help?
- What if the header must be stored as a string?
From the lesson Slices: length, capacity, append and aliasing
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
RemoveAt(s []int, i int) []int returns append(s[:i], s[i+1:]...). A caller removes index 2 from [1 2 3 4 5], prints its own slice and sees [1 2 4 5 5]. Explain the output, then design the function's API.
- What it tests
- Knowing how an in-place removal shifts elements inside the caller's array, reading the contract of slices.Delete, and choosing between an in-place and a copying API.
- First step
- s[:i] keeps the caller's array and capacity, so the append writes 4 and 5 over the caller's elements 2 and 3 and returns a header of length 4. The caller's own header still has length 5, so it shows the shifted elements followed by the old last element.
- Follow-ups
-
- What does slices.Delete do about the element left at the end?
- When is the in-place version the right choice?
- What changes for a slice of pointers?
From the lesson Slices: length, capacity, append and aliasing
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A code review finds slices.SortFunc(accounts, func(a, b Account) int { return int(a.Balance - b.Balance) }) with int64 balances, where math.MinInt64 marks an account with no balance yet. The tests pass. What can go wrong, and what do you write instead?
- What it tests
- Knowing that a comparison must give the right sign for every pair, that integer subtraction wraps on overflow, and using cmp.Compare and cmp.Or.
- First step
- Check the sign of a.Balance - b.Balance for extreme values. For 500 and math.MinInt64 the true difference is about 9.2 billion billion, past the largest int64, so it wraps to a negative number and says 500 sorts before the marker. The sort trusts the sign, so the result is out of order, with no error.
- Follow-ups
-
- Why do the tests pass?
- What happens with uint32 ids and the same subtraction?
- How do you sort the accounts with no balance last?
From the lesson The slices package: sort, search and compare
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid
A transactions page sorts its rows by date with slices.SortFunc. Users report that rows with the same date change places when they refresh, but the tests, which use ten rows, always pass. Explain both observations and fix it.
- What it tests
- Knowing that SortFunc is not stable, why a small test can still look stable, and fixing the order with SortStableFunc or a final key that never ties.
- First step
- Name the guarantee: SortFunc's documentation does not promise to keep equal elements in their order. Rows with one date tie, so their order depends on the sort's moves, and on the order the rows arrived in from the database, which can differ between requests. Then ask what the sort does differently with ten rows than with hundreds.
- Follow-ups
-
- Why does a test with ten rows never fail?
- SortStableFunc or a last key, which do you choose?
- What does the database have to do with it?
From the lesson The slices package: sort, search and compare
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A service checks each request against one million blocked ids kept in a sorted slice with slices.BinarySearch. A new feature appends ids to the end of the slice as they are reported, and some blocked ids now get through. Why, and how do you keep the check correct and fast?
- What it tests
- Knowing that binary search requires sorted input and fails silently, the cost of inserting into a sorted slice, and choosing between sorted inserts, batch sorting and a map.
- First step
- Recall what the search assumes: the slice is sorted, so each look throws away half of it. An appended id that is smaller than its neighbours sits in a part the search has already thrown away, so it reports not found without any error. The check is now wrong for exactly the newest ids.
- Follow-ups
-
- What does inserting each new id in its sorted place cost at a million ids?
- Would a map be better here?
- How do you update the list while requests are being checked?
From the lesson The slices package: sort, search and compare
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
An HTTP service keeps sessions in a package-level map[string]Session that every handler reads and writes. Under load it dies with fatal error: concurrent map writes, and the recover in its middleware never runs. Explain why, then fix it and say how you would catch it in tests.
- What it tests
- Knowing that maps are unsafe under concurrent writes, what the runtime's check does to a program, choosing between a mutex and sync.Map, and testing with the race detector.
- First step
- Handlers run in their own goroutines, so two requests can write the map at once, which Go does not allow, and the runtime's check stopped the program. Read the first word of the message, fatal, and ask what a fatal error does to deferred calls, which is where the middleware's recover lives.
- Follow-ups
-
- Why can't recover catch it?
- Mutex, RWMutex or sync.Map, which do you choose here?
- How do you find it before production?
From the lesson Maps: lookups, sets, iteration and gotchas
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A cache map held 10 million entries at a traffic peak. A nightly purge deletes all but 50,000 of them, yet the process's heap stays near its peak for days. Explain what you see, and fix it without restarting the process.
- What it tests
- Knowing that a Go map keeps its storage after deletes and clear, measuring it, and rebuilding or bounding the map safely while it is in use.
- First step
- Measure before guessing: after a garbage collection the heap stays at the peak, so something still owns the memory. Look at the map itself: deleting an entry frees its slot for a later insert, but nothing says the map gives back the storage it grew to at the peak.
- Follow-ups
-
- Does clear give the memory back?
- How do you rebuild the map while requests use it?
- How would you keep it from peaking in the first place?
From the lesson Maps: lookups, sets, iteration and gotchas
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
byUser is a map[string]Stats, and byUser[id].Visits++ does not compile. Explain the error, give two ways to make the change, and say when each fits.
- What it tests
- Knowing that map elements are not addressable, writing a copy back or storing pointers, and the trade-offs of each, including range loops that change copies.
- First step
- Read the message: cannot assign to struct field byUser[id].Visits in map. Ask what the left side of an assignment may be, and whether a map element is one of those things; both ways to make the change follow from the answer.
- Follow-ups
-
- Why does a range loop that sets s.Visits = 0 change nothing?
- What do pointers in the map cost and risk?
- Does the same rule apply to a slice of structs?
From the lesson Maps: lookups, sets, iteration and gotchas
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid
A notification service shortens each message to fit a 160-byte field with msg[:160]. Messages in Hindi sometimes end in a replacement character on phones. Explain what happens, fix it, and say what can still go wrong with emoji.
- What it tests
- Knowing that slicing a string cuts bytes, that UTF-8 characters take several bytes, cutting at a rune boundary, and the limits of rune-level cutting for grapheme clusters.
- First step
- Count bytes, not letters: each Devanagari code point takes three bytes in UTF-8, so a cut at byte 160 can land inside one, leaving one or two of its bytes at the end. Those bytes are invalid UTF-8, and the phone shows the replacement character in their place.
- Follow-ups
-
- How do you cut to at most 160 bytes and stay valid?
- What if the limit is 160 characters instead of bytes?
- What can still break with emoji and Devanagari conjuncts?
From the lesson Strings, bytes and runes: UTF-8 done right
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A report builder adds 50,000 lines of about 40 bytes to a string with report += line, and the job is slow and uses far more memory than the 2 MB report. Explain the cost with numbers and rewrite it.
- What it tests
- Knowing that strings are immutable so += copies the text so far, estimating quadratic copying, and using strings.Builder, Grow and strings.Join.
- First step
- Follow one +=: a string cannot change, so it allocates a new string and copies the whole report so far plus the line. The k-th line copies about k × 40 bytes, so 50,000 lines copy about 40 × 50,000² / 2 bytes, some 50 GB, for a report of 2 MB.
- Follow-ups
-
- How many allocations does each version make?
- When is += fine?
- What does Grow add, and how do you size it?
From the lesson Strings, bytes and runes: UTF-8 done right
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A sign-up form must limit usernames to 20 characters. The Go check len(name) > 20 rejects many names written in Devanagari that look short. What should "characters" mean here, and how do you implement and test the limit?
- What it tests
- Knowing the difference between bytes, runes and grapheme clusters, choosing the unit a rule means, validating UTF-8 and normalising input, and testing with scripts beyond ASCII.
- First step
- Name the three units: len counts bytes, three per Devanagari code point, so a 7-letter name can pass 20 bytes; utf8.RuneCountInString counts code points; what a user sees as a character is a grapheme cluster, which can be several runes. Decide which one the rule means, then measure that.
- Follow-ups
-
- Why is a rune count not what users count?
- What else must the check do before counting?
- Which test cases would you write?
From the lesson Strings, bytes and runes: UTF-8 done right
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A CSV import reads quantities with strconv.ParseInt(field, 10, 8) to save memory, logs any error and stores the returned value. A row with 300 is stored as 127. Explain what happened and fix the import.
- What it tests
- Knowing that ParseInt returns the limit of the bit size together with ErrRange, never using a value after an error, and choosing a bit size from the data.
- First step
- Read what ParseInt promises on a range error: the returned value is the largest magnitude of the bit size and sign, 127 for 8 bits, together with ErrRange. The import logged the error but stored the value anyway, so every quantity above 127 became 127, and every one below -128 became -128.
- Follow-ups
-
- Why is the value not 0, as it is for a syntax error?
- Which bit size should the field use?
- How should the import report the bad row?
From the lesson Numbers as text: strconv, bases and grouping
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid
An API answers bad query parameters with the error text from strconv, such as strconv.ParseInt: parsing "12a": invalid syntax. What is wrong with that, and how do you turn a *strconv.NumError into good messages?
- What it tests
- Knowing NumError's fields and errors.Is with ErrSyntax and ErrRange, writing messages that name the field and the rule, and keeping internal names and raw input out of responses.
- First step
- Read it as the client does: it names a Go function the client never called, and says neither which parameter was wrong nor what is allowed. The error holds what a better message needs: errors.Is with strconv.ErrSyntax or strconv.ErrRange gives the kind of mistake, and the code that parsed knows the field and its rule.
- Follow-ups
-
- What should the message contain?
- Should the response repeat the input?
- How do you test the messages?
From the lesson Numbers as text: strconv, bases and grouping
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
Write FormatAmount(paise int64) string, which prints amounts with Indian digit grouping, such as 12,34,567.89. Which edge cases must its tests cover, and why does each one exist?
- What it tests
- Knowing integer division and remainder for minor units, the grouping rule, the sign of remainders, and the int64 edge at math.MinInt64.
- First step
- Keep the amount an integer: the rupees are the amount divided by 100, and the paise are the remainder, printed with two digits. Group the rupee digits from the right, three first and then pairs. Then test the obvious version at the edges of int64 and with negative amounts before you trust it.
- Follow-ups
-
- Why not divide a float64 by 100?
- What goes wrong with negative amounts?
- How would you also support grouping by threes?
From the lesson Numbers as text: strconv, bases and grouping
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes