Interfaces Basics — Find the Bug¶
Bug 1 — Pointer receiver method, value satisfies?¶
Bug: Compile error. M is not in T's method set (pointer receiver). Fix:var i I = &T{}. Bug 2 — nil interface¶
type MyErr struct{}
func (e *MyErr) Error() string { return "err" }
func doit() error {
var e *MyErr
return e
}
err := doit()
if err != nil {
fmt.Println("got error")
}
got error. The interface (type: MyErr, value: nil) is NOT nil. Fix:* Bug 3 — Comparison panic¶
type S struct{ items []int }
var i, j any = S{items: []int{1}}, S{items: []int{1}}
fmt.Println(i == j)
Bug 4 — A new method was added¶
// v1
type Repo interface { Find(id string) (*User, error) }
// Concrete
type Mock struct{}
func (m *Mock) Find(id string) (*User, error) { return nil, nil }
// v2 — new method added
type Repo interface {
Find(id string) (*User, error)
Save(u *User) error // NEW
}
Bug 5 — fmt.Sprint inside Stringer¶
Bug:fmt.Sprint(x) calls String() — infinite recursion → stack overflow. Fix: Bug 6 — Interface receiver¶
Bug: Compile error. You cannot add a method to an interface type. Fix: Add the method to a concrete type.Bug 7 — Type assertion mismatch¶
Bug: Runtime panic — i is an int. Fix:Bug 8 — Mixed receiver interface¶
type S struct{}
func (s S) Read() {}
func (s *S) Write() {}
type RW interface { Read(); Write() }
var x RW = S{}
var x RW = &S{}. Bug 9 — Interface bloat¶
type FullStorage interface {
Read(...) ...
Write(...) ...
Delete(...) ...
List(...) ...
Backup(...) ...
Restore(...) ...
Verify(...) ...
Migrate(...) ...
}
Bug 10 — Same name, different signatures¶
Bug: Compile error — incompatible methods. Fix: Make the signatures compatible or rename them.Bug 11 — Empty interface comparison¶
Bug: Runtime panic — functions are not comparable. Fix: Do not use== on functions. If you need an identity check — use a different approach. Bug 12 — Compile-time check missing¶
type Reader interface { Read([]byte) (int, error) }
type MyReader struct{}
func (r *MyReader) Read(p []byte) (int, error) { return 0, nil }
// Usage
func process(r Reader) { r.Read(nil) }
process(&MyReader{})
Bug 13 — Returning concrete type vs interface¶
func NewLogger() Logger {
return &ConsoleLogger{}
}
func main() {
l := NewLogger()
l.SpecialMethod() // Logger interface has no SpecialMethod
}
Logger interface — concrete methods cannot be used. Fix: Return concrete: Or use a type assertion:
Bug 14 — Interface embedding loop¶
Bug: Compile error — circular embedding. Fix: Make the hierarchy explicit.Bug 15 — Method on a non-defined type¶
Bug: Compile error. You cannot add methods to an alias. Fix:Bug 16 — Assigning concrete to interface¶
type Logger interface { Log(string) }
type FullLogger struct{}
func (FullLogger) Log(string) {}
func (FullLogger) Stats() Stats { return Stats{} }
func main() {
var l Logger = FullLogger{}
l.Stats() // Logger has no Stats
}
Bug 17 — nil interface dereference¶
Bug: Panic — nil interface dispatch. Fix: Nil check or always initialize.Bug 18 — Returning nil interface with concrete¶
func loadConfig() Config {
return nil // even though Config is an interface, no concrete type is provided
}
nil concrete type is required. Or — in the interface case it is OK, but the caller can check c == nil. Bug 19 — Method receiver name inconsistency¶
Not a bug, but a style issue: Receiver names should be consistent. Fix: Uses everywhere.