Prev Next

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#? 2. What is the internal two-word structure of a Go interface value? 3. Explain the nil interface trap in Go. Why does a typed nil fail the '!= nil' check? 4. How does Go's implicit interface satisfaction enable duck typing and loose coupling? 5. What is the empty interface (any) in Go and what are its trade-offs? 6. What is the difference between value receivers and pointer receivers in Go methods? 7. How does interface embedding (composition) work in Go? 8. How does Go achieve runtime polymorphism using interfaces? 9. How does Go implement code reuse without inheritance? Explain composition via struct embedding. 10. How does embedding help a struct satisfy an interface? 11. How is the built-in error type defined and how do you implement custom errors? 12. What is the fmt.Stringer interface and how do you implement it? 13. How do type assertions work on interface values and when do you use them? 14. Explain the Go design principle: 'Accept interfaces, return concrete types'. 15. How do Go interfaces enable dependency injection and improve testability? 16. How do you sort custom types using sort.Interface in Go? 17. How do io.Reader and io.Writer demonstrate Go's interface design philosophy? 18. Why can't you always use a value of type T where *T is needed for interface satisfaction? 19. How can a single Go type implement multiple interfaces simultaneously? 20. How does Go implement encapsulation without private/public class modifiers? 21. How do the fmt.Stringer and error interfaces work together and how do you avoid infinite recursion? 22. How do generics relate to interfaces in Go 1.18+ and what are type constraints? 23. How do you implement an abstract type pattern in Go using interfaces and constructors? 24. What is the compile-time interface check idiom and why is it important? 25. How does equality work for interface values in Go? 26. How does the io.Closer interface work with defer for resource management? 27. How does Go differ from classical OOP in terms of inheritance and method overriding? 28. How does http.Handler demonstrate real-world interface design in Go? 29. What is the function-as-interface pattern in Go and how does it enable flexible APIs? 30. What is interface pollution and how do you avoid it in Go? 31. What is the difference between fmt.Stringer and fmt.GoStringer? 32. How does Go's standard library use interface layering for I/O transformation? 33. When should you use reflection instead of interfaces for type-agnostic code in Go? 34. How does thinking about interfaces as 'behaviours, not data' guide better design? 35. What is the interface upgrade (optional interface) pattern in Go? 36. What is the difference between embedding a struct and embedding an interface inside a struct? 37. Are interface values in Go safe to use concurrently? 38. How do you combine table-driven tests with interface mocks in Go? 39. How is context.Context an interface and how does its design demonstrate Go best practices? 40. How does Go embody the Interface Segregation Principle (ISP)? 41. How do type aliases and type definitions differ in relation to interface satisfaction in Go? 42. How does embedding propagate interface satisfaction through multiple levels? 43. What is the zero value of an interface type and how does it differ from a zero-value struct? 44. How do you use wrapper types to adapt existing types to satisfy interfaces in Go? 45. Walk through a complete Go OOP design: payment processing without inheritance. 46. What are the edge cases in Go interface value equality that trip up experienced developers? 47. What is sync.Locker and how is it used in real-world Go concurrency code? 48. Summarise the key rules and best practices for Go interfaces that interviewers test.

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...

Read full answer

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...

Read full answer

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 ...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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 ...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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 ...

Read full answer

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 ...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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 ...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

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 } ...

Read full answer

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...

Read full answer

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...

Read full answer

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 ─────────────â”...

Read full answer

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...

Read full answer

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...

Read full answer

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...

Read full answer

«
»

Comments & Discussions