mediumBackend EngineerTechnology
How do Go interfaces work implicitly, and why is this different from Java/C# explicit interfaces?
Posted 18/04/2026
by Mehedy Hasan Ador
Question Details
At a company transitioning from Java to Go:
> "In Java, we'd write
> "In Java, we'd write
class Dog implements Animal. In Go, there's no implements keyword. How does Go's interface system work, and what are the design implications?"Suggested Solution
Go Interfaces — Implicit Satisfaction
// Define interface
type Storer interface {
Store(data []byte) error
Retrieve(id string) ([]byte, error)
}
// Implement interface — NO "implements" keyword needed
type RedisStore struct { client *redis.Client }
func (r *RedisStore) Store(data []byte) error {
return r.client.Set("key", data, 0).Err()
}
func (r *RedisStore) Retrieve(id string) ([]byte, error) {
return r.client.Get(id).Bytes()
}
// RedisStore AUTOMATICALLY satisfies Storer
// Compiler checks at usage site, not definition site
var store Storer = &RedisStore{} // ✅ Compiles!
Why Implicit Is Better
The "Accept Interfaces, Return Structs" Rule
// ✅ Good: Accept interface for flexibility
func ProcessData(store Storer, data []byte) error {
return store.Store(data)
}
// In tests:
type MockStore struct{}
func (m *MockStore) Store(data []byte) error { return nil }
func (m *MockStore) Retrieve(id string) ([]byte, error) { return nil, nil }
ProcessData(&MockStore{}, testData) // Easy mocking!
Empty Interface (interface{})
// Accepts ANY type (like Object in Java, any in TS)
func Print(v interface{}) {
fmt.Println(v)
}
// Prefer typed interfaces or generics over interface{}
Type Assertion & Type Switch
func handle(v interface{}) {
switch val := v.(type) {
case string:
fmt.Println("String:", val)
case int:
fmt.Println("Int:", val)
default:
fmt.Println("Unknown:", val)
}
}