Golang / GoLang Interfaces and Object Oriented Interview Questions
1. What is an interface in Go and how does it differ from interfaces in Java or C#?
In Go, an interface is a named set of method signatures. Any concrete type that implements all the methods in the set automatically satisfies the interface — no declaration, no implements keyword, no registration is required. This property is called implicit (or structural) interface satisfaction...
2. What is the internal two-word structure of a Go interface value?
Internally, every non-empty interface value is a two-word pair stored on the stack (or heap if it escapes): Interface Value Layout Word Name Content Word 1 itab (type word) Pointer to an itab struct containing: the interface type descriptor, the concrete type descriptor, a hash of the concrete ty...
3. Explain the nil interface trap in Go. Why does a typed nil fail the '!= nil' check?
This is one of the most frequently asked Go interview questions. The trap: an interface value is only nil when both its type pointer and its data pointer are zero. If you assign a nil pointer of a concrete type to an interface variable, the type pointer becomes non-zero — so the interface is not ...
4. How does Go's implicit interface satisfaction enable duck typing and loose coupling?
Go's implicit interface satisfaction means: if a type has the required methods, it satisfies the interface — regardless of whether the type's author ever heard of that interface. This is sometimes called structural typing or duck typing with compile-time verification . // Third-party library defi...
5. What is the empty interface (any) in Go and what are its trade-offs?
The empty interface interface{} — aliased as any since Go 1.18 — has no methods. Because every type implements zero or more methods, every type satisfies the empty interface. It is Go's equivalent of Java's Object or C's void* . // any is an alias for interface{} (Go 1.18+) func printAnything(v a...
6. What is the difference between value receivers and pointer receivers in Go methods?
Go methods are functions associated with a type. The receiver appears before the method name: func (t T) Method() (value receiver) or func (t *T) Method() (pointer receiver). Choosing correctly is essential for correctness and performance. type Counter struct { count int } // Value receiver â o...
7. How does interface embedding (composition) work in Go?
Go interfaces can embed other interfaces. The composed interface's method set is the union of all embedded interface method sets. This is Go's primary mechanism for building larger interface contracts from smaller, focused ones — following the Interface Segregation Principle. // Small, focused in...
8. How does Go achieve runtime polymorphism using interfaces?
Go achieves polymorphism through interface dispatch. When you call a method on an interface value, the runtime uses the itab 's function pointer table to call the correct concrete implementation. This is equivalent to virtual method dispatch in C++ or Java. type Shape interface { Area() float64 P...
9. How does Go implement code reuse without inheritance? Explain composition via struct embedding.
Go has no class hierarchy and no inheritance. Code reuse is achieved through composition : embedding one struct inside another promotes the embedded type's methods and fields to the outer type. This gives the outer type the embedded type's capabilities without any parent-child relationship. // Ba...
10. How does embedding help a struct satisfy an interface?
When a struct embeds another type, it promotes the embedded type's methods. If those promoted methods complete an interface's method set, the outer struct implicitly satisfies the interface — without writing any wrapper code. type Sayer interface { Say() string } type Greeter struct {} func (g Gr...
11. How is the built-in error type defined and how do you implement custom errors?
The error type is Go's built-in interface for representing error conditions. It has exactly one method: type error interface { Error() string } Any type that has an Error() string method satisfies the error interface. This makes error handling in Go extremely flexible — you can attach arbitrary c...
12. What is the fmt.Stringer interface and how do you implement it?
The fmt.Stringer interface is the standard Go convention for providing a human-readable string representation of a type. It is used automatically by fmt.Print , fmt.Println , and %v / %s format verbs. // Interface definition (in the fmt package) type Stringer interface { String() string } // Cust...
13. How do type assertions work on interface values and when do you use them?
A type assertion extracts the concrete value from an interface variable. There are two forms: the single-return form that panics on failure, and the comma-ok form that returns a boolean. type Animal interface { Sound() string } type Dog struct { Name string } func (d Dog) Sound() string { return ...
14. Explain the Go design principle: 'Accept interfaces, return concrete types'.
This principle appears in Russ Cox's writings and the Go wiki. It guides the design of clean, testable, and composable APIs. Accept interfaces : function parameters typed as interfaces are flexible — callers can pass any concrete type satisfying the interface, including mocks in tests. Return con...
15. How do Go interfaces enable dependency injection and improve testability?
Because Go interfaces are satisfied implicitly, any dependency can be injected as an interface. In tests, the interface is replaced with a mock or stub — without any framework, reflection, or code generation. // Production dependency: HTTP client type HTTPClient interface { Get(url string ) ( * h...
16. How do you sort custom types using sort.Interface in Go?
sort.Interface is one of Go's classic interface examples. Any type that implements three methods can be sorted by sort.Sort : // sort.Interface definition: type Interface interface { Len() int Less(i, j int ) bool Swap(i, j int ) } // Custom type implementing sort.Interface type Person struct { N...
17. How do io.Reader and io.Writer demonstrate Go's interface design philosophy?
io.Reader and io.Writer are the most influential interfaces in the Go standard library. They each have exactly one method, yet they model an enormous variety of data sources and sinks — files, network connections, byte buffers, compression streams, crypto pipes, and more. // io.Reader and io.Writ...
18. Why can't you always use a value of type T where *T is needed for interface satisfaction?
Go's method set rules determine which methods can be called on a value of a given type. The asymmetry is: Go Method Set Rules Type in expression Method set T (value type) Only methods declared with value receiver (func (t T)) *T (pointer type) Methods declared with value receiver + methods with p...
19. How can a single Go type implement multiple interfaces simultaneously?
A type can implement any number of interfaces simultaneously — all it needs is the right set of methods. There is no limit and no explicit declaration. This enables a type to play many roles in different contexts. // Several independent interfaces type Saver interface { Save() error } type Loader...
20. How does Go implement encapsulation without private/public class modifiers?
Go's encapsulation is package-level , not class-level. Identifiers (types, fields, functions, methods) are exported (public) if they start with an uppercase letter, and unexported (package-private) if they start with a lowercase letter. There is no private , protected , or public keyword. // pack...
21. How do the fmt.Stringer and error interfaces work together and how do you avoid infinite recursion?
Types often implement both fmt.Stringer ( String() string ) and error ( Error() string ). A subtle trap: inside String() , calling fmt.Sprintf("%v", e) on the receiver causes infinite recursion because %v checks for Stringer and calls String() again. type AppError struct { Code int Message string...
22. How do generics relate to interfaces in Go 1.18+ and what are type constraints?
Go 1.18 extended the interface syntax so interfaces can serve as type constraints for generic functions and types. A constraint specifies which types a type parameter can be. Constraints are just interfaces — but now interfaces can include concrete type lists in addition to method sets. // Constr...
23. How do you implement an abstract type pattern in Go using interfaces and constructors?
Go has no abstract class . The idiomatic equivalent is: define an interface for the contract, provide a factory function that returns the interface, and keep the concrete implementation unexported. Callers depend only on the interface — the implementation is hidden. // database/db.go â abstract...
24. What is the compile-time interface check idiom and why is it important?
Because Go interface satisfaction is implicit, the compiler normally checks it only at the point of actual use (assignment or function call). If a type is exported and expected to satisfy an interface, a change to the type's method set might silently break the contract — only catching the error a...
25. How does equality work for interface values in Go?
Two interface values are equal ( == ) if and only if both their dynamic type and dynamic value are identical . If either interface is nil, both must be nil for equality. Comparing interfaces whose dynamic type is not comparable panics at runtime. type Animal interface { Sound() string } type Dog ...
26. How does the io.Closer interface work with defer for resource management?
io.Closer is a single-method interface used to release resources. Combined with defer , it provides Go's idiomatic resource management pattern — analogous to try-with-resources in Java or RAII in C++. // io.Closer definition type Closer interface { Close() error } // Pattern 1: defer immediately ...
27. How does Go differ from classical OOP in terms of inheritance and method overriding?
Go deliberately omits classical inheritance. The Go FAQ explains this choice: inheritance creates tight coupling between classes, makes hierarchies rigid, and encourages deep class trees that are hard to refactor. Go replaces inheritance with composition and interfaces. OOP Concept Mapping OOP Co...
28. How does http.Handler demonstrate real-world interface design in Go?
http.Handler is one of Go's most widely used interfaces. It models exactly one behaviour — handling an HTTP request — with a single method. The entire net/http server is built around this interface, making it extensible, testable, and composable through middleware. // The entire http.Handler inte...
29. What is the function-as-interface pattern in Go and how does it enable flexible APIs?
Go allows you to declare a named function type and attach methods to it — making it satisfy an interface. This eliminates the need for a wrapper struct when the only state needed is the function itself. It is used extensively in net/http , testing, and plugin architectures. // Define an interface...
30. What is interface pollution and how do you avoid it in Go?
Interface pollution means creating interfaces prematurely, needlessly, or with too many methods — when a concrete type would be simpler and clearer. It adds indirection without benefit and makes code harder to navigate. Interface Pollution Signs Anti-pattern Problem Fix Interface with one method ...
31. What is the difference between fmt.Stringer and fmt.GoStringer?
Go's fmt package supports two string-representation interfaces for types. They serve different audiences and contexts: Stringer vs GoStringer Interface Method Format Verb Purpose fmt.Stringer String() string %v, %s Human-readable output for logs, CLI, user-facing text fmt.GoStringer GoString() st...
32. How does Go's standard library use interface layering for I/O transformation?
The I/O stack in Go is built by wrapping interfaces. Each layer satisfies io.Reader or io.Writer and wraps the previous layer, adding one transformation: buffering, compression, encryption, counting. No layer modifies the others — they compose transparently. // Layer by layer: file â gzip â b...
33. When should you use reflection instead of interfaces for type-agnostic code in Go?
Both interfaces and reflection allow code to work with values of unknown types at runtime, but they differ fundamentally in safety, performance, and intent. Interfaces vs Reflection Aspect Interface Reflection (reflect package) Type safety Compile-time method set checked Fully runtime — panics on...
34. How does thinking about interfaces as 'behaviours, not data' guide better design?
In Go, the best interfaces describe what something does , not what something is . Names ending in -er (Reader, Writer, Closer, Logger, Handler) signal a single behaviour. This contrasts with Java-style interfaces like IUserRepository that mirror a class's public API. // Behaviour-based (Go idioma...
35. What is the interface upgrade (optional interface) pattern in Go?
The interface upgrade pattern lets code check whether an interface value's concrete type also satisfies a more capable (optional) interface, and use the enhanced behaviour if available — without requiring all implementations to support it. This is how the Go standard library achieves extensibilit...
36. What is the difference between embedding a struct and embedding an interface inside a struct?
Both look syntactically similar but have very different semantics and use cases: Struct Embedding vs Interface Embedding Aspect Embed a struct Embed an interface Promoted methods Real implementations from the embedded struct Method signatures only — calls the interface field's concrete value Zero...
37. Are interface values in Go safe to use concurrently?
Interface values are not inherently goroutine-safe . An interface value is a two-word struct (type pointer + data pointer). Assigning to an interface variable is not atomic — a goroutine reading the interface while another is writing it can observe a partially written state (mismatched type and d...
38. How do you combine table-driven tests with interface mocks in Go?
The two most important Go testing patterns together: table-driven tests for coverage and interface mocks for isolation. Combining them gives thorough, readable, and maintainable tests for any component that has external dependencies. // System under test type UserEmailer interface { GetEmail(user...
39. How is context.Context an interface and how does its design demonstrate Go best practices?
context.Context is a four-method interface that carries deadlines, cancellation signals, and request-scoped values across API boundaries. Its design exemplifies Go's interface philosophy: small, behaviour-focused, implicitly satisfied, and composable. // The full context.Context interface: type C...
40. How does Go embody the Interface Segregation Principle (ISP)?
The Interface Segregation Principle states: clients should not be forced to depend on methods they do not use. Go's implicit, structural interfaces make ISP trivially achievable — any consumer can define the minimal interface it needs, independently of what the concrete type exposes. // A concret...
41. How do type aliases and type definitions differ in relation to interface satisfaction in Go?
Go distinguishes between type definitions ( type MyInt int ) and type aliases ( type MyInt = int ). They behave very differently when it comes to interface satisfaction and method sets. // TYPE DEFINITION â creates a new, distinct type type Celsius float64 type Fahrenheit float64 // Celsius and...
42. How does embedding propagate interface satisfaction through multiple levels?
Embedding is transitive. If type C embeds type B which embeds type A, then C's method set includes all methods from A and B. This means C can satisfy interfaces that A satisfies — through a chain of embeddings. type Named interface { Name() string } type Described interface { Describe() string } ...
43. What is the zero value of an interface type and how does it differ from a zero-value struct?
Understanding zero values is essential for correct initialisation. Interface and struct zero values behave very differently. // Zero value of a struct â all fields zeroed type Config struct { Host string ; Port int ; Debug bool } var cfg Config // zero value: Config{Host:"", Port:0, Debug:false...
44. How do you use wrapper types to adapt existing types to satisfy interfaces in Go?
Sometimes an existing type almost satisfies an interface but has a slightly different method signature. Rather than modifying the original type (which may be in another package), you can wrap it in a new type that adapts the interface. // Standard logger â method signature doesn't match our int...
45. Walk through a complete Go OOP design: payment processing without inheritance.
A realistic scenario showing how Go's interfaces, composition, and implicit satisfaction replace classical OOP: a payment processing system that is extensible, testable, and loosely coupled — without a single inheritance relationship. // ââ Interfaces ââââââââââââââ...
46. What are the edge cases in Go interface value equality that trip up experienced developers?
Interface equality has several subtle edge cases that are distinct from what most developers expect: // Case 1: nil interface vs interface holding nil pointer var p * int var i interface {} = p // i has type *int, data nil fmt.Println(p == nil ) // true â p is a nil pointer fmt.Println(i == nil...
47. What is sync.Locker and how is it used in real-world Go concurrency code?
sync.Locker is a small two-method interface from the standard library. It is satisfied by both *sync.Mutex and *sync.RWMutex , as well as any custom lock type. It is used to write generic lock-based utilities. // sync.Locker interface: type Locker interface { Lock() Unlock() } // Both *sync.Mutex...
48. Summarise the key rules and best practices for Go interfaces that interviewers test.
This summary covers the most frequently tested interface rules in Go technical interviews: Go Interface Cheat Sheet Rule Detail Implicit satisfaction No 'implements' keyword — matching method set is sufficient Method set (value) T has only value-receiver methods in its method set Method set (poin...