Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Go Module 5

Structs, pointers and methods interview questions

Interview questions on structs, pointers and methods: short warm-ups, then what each harder question tests, the first step of a good answer and its follow-ups.

20 questions: 5 warm-ups and 15 with model answers · Levels: Fresher to senior

Warm-up questions

Short questions with short answers, each answered in full.

  1. Fresher

    What is the difference between a keyed and a positional struct literal?

    Answered in the lesson Structs and struct literals, including Go 1.27

  2. Fresher

    What does new return, and how does new(29) differ from new(int)?

    Answered in the lesson Pointers, new and escape analysis

  3. Fresher

    What is a method receiver in Go?

    Answered in the lesson Methods: value and pointer receivers

  4. Fresher

    Is embedding in Go the same as inheritance?

    Answered in the lesson Embedding: composition instead of inheritance

  5. Fresher

    Name two standard-library types whose zero value is ready to use, and say what that means.

    Answered in the lesson Constructors, useful zero values and options

Questions with model answers

What each question tests, the first step of a good answer and the follow-ups to expect.

  1. Fresher to mid

    Your team upgrades a shared package, and three services stop compiling with too few values in struct literal of type rail.Seat. The package only added a field to Seat. Explain why, how you fix the services, and how you keep it from happening again.

    What it tests
    Knowing that positional literals list every field while keyed ones survive new fields, what go vet's composites check reports, and how a package can be designed to grow.
    First step
    Find the failing literals: each lists Seat's fields by position, rail.Seat{"B2", 34}, so a third field leaves it one value short. Rewrite each with keys, rail.Seat{Coach: "B2", Berth: 34}, which compiles whatever fields Seat gains, and run go vet on every service to find the positional literals that have not broken yet.
    Follow-ups

    From the lesson Structs and struct literals, including Go 1.27

    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.

    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
  2. Mid to senior

    A booking service must spot duplicate bookings: the same passenger, train, travel day and berth. A teammate keys a map by one string joined from the four values with a | between them. Would you use a struct key instead? Design the key and say what can go wrong with each choice.

    What it tests
    Knowing which types are comparable, struct keys against joined string keys, separator collisions, normalising values before building a key, and which field types make a poor key.
    First step
    List the values that identify a booking and check that each is comparable: strings and integers are, slices are not. A struct of them, bookingKey{Passenger, Train string; Day, Berth int}, is a valid key that compares field by field, so it cannot collide the way joined text can, provided every value is normalised the same way first.
    Follow-ups

    From the lesson Structs and struct literals, including Go 1.27

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  3. Mid to senior

    A service keeps 20 million fare records in memory, each a struct of a bool, an int64, a bool, an int32 and a byte, in that order. Memory use is higher than the fields suggest. How do you measure what the struct costs, what do you change, and what do you check before changing it?

    What it tests
    Measuring size and offsets with package unsafe, explaining alignment padding, estimating the saving at scale, and weighing it against readability and the tools that suggest an order.
    First step
    Measure before changing anything: unsafe.Sizeof and unsafe.Offsetof show 32 bytes per record, 17 of them padding, because the int64 must start at a multiple of 8. With the int64 first and the small fields together the same fields take 16 bytes, so 20 million records shrink from 640 MB to 320 MB.
    Follow-ups

    From the lesson Structs and struct literals, including Go 1.27

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  4. Fresher to mid

    Profile has an Age *int field. A handler copies a profile, sets the copy's age and saves the copy, and the original profile's age changes too. Explain what happened, and fix the handler so that the two profiles stay independent.

    What it tests
    Knowing what copying a struct does to a pointer field, comparing pointers, giving a copy a variable of its own, and spotting the same trap in slice and map fields.
    First step
    Find where the second profile came from. If it was assigned or passed from the first, compare the two Age fields with ==: equal pointers mean that both profiles reach one int, so a write through either one is seen through the other.
    Follow-ups

    From the lesson Pointers, new and escape analysis

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 2 minutes
  5. Mid to senior

    In a code review, a teammate asks you to change func NewOrder(id string) *Order to return an Order, because returning pointers is slow. How do you decide, and what do you measure before changing it?

    What it tests
    Knowing that escape analysis decides heap allocation, measuring allocations and their cost, and weighing copying, identity and the conventions of an API.
    First step
    Separate the claim from the evidence. Returning a pointer to a new Order does make the Order a heap allocation, while returning the value lets the caller keep it where it likes; whether that matters depends on how often NewOrder runs and on what the caller does with the result, which a measurement shows and a rule does not.
    Follow-ups

    From the lesson Pointers, new and escape analysis

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  6. Mid to senior

    After a Go toolchain upgrade, a service that ran for years starts to panic with a nil pointer dereference in a function that opens a file and reads its name. Nobody changed the function. How do you investigate, and what do you fix?

    What it tests
    Reading a panic's stack trace, knowing that a failed call may return nil results with its error, checking errors before using results, and how a compiler fix can expose an old bug.
    First step
    Read the stack trace to find the line that panicked, then look at the order of the statements around it: which value is nil on that line, which call produced it, and whether that call's error is checked before or after the line.
    Follow-ups

    From the lesson Pointers, new and escape analysis

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  7. Fresher to mid

    A Wallet type has Credit and Debit methods. Its tests check only the errors the methods return, and they pass, but in production a balance never goes down after a debit. Debit is declared as func (w Wallet) Debit(amount int) error. Explain the bug, and how you keep it from coming back.

    What it tests
    Knowing that a value receiver works on a copy, why the compiler accepts it, writing tests that check state, and keeping the receivers of a type consistent.
    First step
    Read Debit's receiver: (w Wallet) is a copy, so the method subtracts from the copy and returns, and the caller's wallet keeps its balance. Then read what the tests assert: the error, which the copy computes correctly, but never the balance after the call.
    Follow-ups

    From the lesson Methods: value and pointer receivers

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 2 minutes
  8. Mid to senior

    A teammate puts Account values in a []Depositor and gets: cannot use acc as Depositor value, method Deposit has pointer receiver. They propose giving Deposit a value receiver so that it compiles. What do you tell them, and what do you change instead?

    What it tests
    Knowing the method sets of T and *T, why an interface cannot call a pointer method on a value it holds, and choosing between values and pointers in a collection.
    First step
    Ask what Deposit has to do. It changes the balance, so a value receiver would make the code compile and silently stop the deposits from arriving. The compiler is pointing at the real decision: whether the slice should hold the accounts themselves or pointers to them.
    Follow-ups

    From the lesson Methods: value and pointer receivers

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  9. Mid to senior

    A request counter holds a sync.Mutex and an int, and its Inc method has a value receiver. Handlers call c.Inc() on a package-level counter, yet the total it reports stays at 0. Explain why, fix it, and say how a tool could have caught it before release.

    What it tests
    Knowing that a value receiver copies the whole struct, mutex included, the rule against copying a Mutex, go vet's copylocks check, and pointer receivers for types that hold a lock.
    First step
    Look at Inc's receiver. With (c Counter), every call copies the counter, its mutex and its int, increments the copy, and drops the copy when Inc returns, so the package-level counter is never written and still reports 0.
    Follow-ups

    From the lesson Methods: value and pointer receivers

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  10. Mid to senior

    A team ports a Java report generator to Go. BaseReport has a Render method that calls r.Header(), and SalesReport embeds BaseReport and declares its own Header. Every sales report renders the base header. Explain why, and redesign it the Go way.

    What it tests
    Knowing that a promoted method resolves its calls on the inner type, that only interfaces dispatch at run time, and turning a template method into an interface or into parts.
    First step
    Look at where Render is declared: on BaseReport, so its receiver is the BaseReport inside SalesReport, and the r.Header() inside it was resolved on BaseReport. Then ask which part of Render really varies from report to report; that part is what the redesign has to pass in.
    Follow-ups

    From the lesson Embedding: composition instead of inheritance

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  11. Mid to senior

    A shared Cache type embeds sync.Mutex so that its methods can call c.Lock(). Months later a production deadlock is traced to a caller in another package that called Lock on a Cache and never released it. What made that possible, and how do you redesign the type?

    What it tests
    Knowing that embedding adds the embedded type's methods to the outer type's API, keeping a lock unexported, and the receivers a type with a mutex needs.
    First step
    List what a caller in another package can call on a *Cache: its own exported methods, and every method promoted from its embedded fields. Then decide which of those a caller should be able to call at all, and which only the Cache's own methods should.
    Follow-ups

    From the lesson Embedding: composition instead of inheritance

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 2 minutes
  12. Mid to senior

    A middleware wraps http.ResponseWriter in a struct that embeds it and counts bytes in its own Write. In one code path the wrapper is built with a nil writer and the handler panics, and streaming endpoints behind the middleware stop flushing. Explain both problems and how you build the wrapper safely.

    What it tests
    Knowing what an embedded interface delegates to, why a nil one panics, that a wrapper has only the methods it embeds or declares, and how Go's HTTP package expects wrappers to expose the original writer.
    First step
    Treat the two failures separately. For the panic, ask what the embedded field holds in the code path that fails. For flushing, compare what the streaming code asks of its writer with what the wrapper itself offers, method by method, and check where each of those methods comes from.
    Follow-ups

    From the lesson Embedding: composition instead of inheritance

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  13. Mid to senior

    You are designing NewClient for a library that 40 services use. It has one required setting, the base URL, and nine optional ones with defaults; one of them, retries, must accept 0. Do you use functional options, a Config struct or something else? Defend the design.

    What it tests
    Separating required from optional settings, the zero-versus-unset problem of config structs, how each design copes with change, checking rules that span settings, and returning a concrete type.
    First step
    Sort the settings first. The base URL has no default, so it is a parameter that the compiler makes every caller pass. Then look at the nine optional ones and ask which can legitimately be 0, because that decides whether a plain struct field can carry them.
    Follow-ups

    From the lesson Constructors, useful zero values and options

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  14. Mid to senior

    During a payment provider's slowdown, a service's goroutine count climbs to 80,000 and it runs out of memory, although its handlers normally finish in milliseconds. The outgoing calls use http.Get. What happened, and how do you change the code and the team's defaults?

    What it tests
    Knowing which client http.Get uses and what its zero Timeout means, how blocked calls hold goroutines, and designing defaults that fail safe.
    First step
    Ask what bounds the duration of each outgoing call. Find which client http.Get uses and what its Timeout is, then work out how long a handler can wait when the provider slows down, and what each waiting handler holds while it waits.
    Follow-ups

    From the lesson Constructors, useful zero values and options

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  15. Mid to senior

    Two teams share a package whose constructor reads an exported variable, DefaultRetries. After one team sets it to 10 in an init function, the other team's service starts sending a payment request up to ten times. Explain what happened and redesign the package.

    What it tests
    Knowing that a package-level variable is one variable for the whole program, how initialisation order hides the cause, why constructors should not read mutable globals, and options or parameters as the fix.
    First step
    Trace where the other team's clients get their retry count. The constructor reads DefaultRetries when it runs, and there is one DefaultRetries for the whole program, so an assignment anywhere, in any package's init function, changes what every later call of the constructor builds.
    Follow-ups

    From the lesson Constructors, useful zero values and options

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes

All Go interview questions · The Go track

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.