Golang / GoLang Interfaces and Object Oriented Interview Questions
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 interface // log.Logger has: func (l *Logger) Printf(format string, v ...any) // Our interface for injecting loggers type Logger interface { Log(msg string) } // Adapter: wraps *log.Logger to satisfy Logger type StdLogger struct{ l *log.Logger } func NewStdLogger(l *log.Logger) Logger { return &StdLogger{l: l} } func (s *StdLogger) Log(msg string) { s.l.Println(msg) } // Now log.Logger can be used anywhere Logger is expected svc := NewService(NewStdLogger(log.Default())) // Adapter for third-party HTTP client â our HTTPClient interface type HTTPClient interface { Do(req *http.Request) (*http.Response, error) } // *http.Client already has Do() â no adapter needed! var client HTTPClient = http.DefaultClient // satisfied out of the box // Reverse adapter: wrap an interface to add a method // LimitedReader wraps io.Reader and adds a counter type CountingReader struct { r io.Reader count int64 } func (cr *CountingReader) Read(p []byte) (int, error) { n, err := cr.r.Read(p) cr.count += int64(n) return n, err } func (cr *CountingReader) BytesRead() int64 { return cr.count } cr := &CountingReader{r: os.Stdin} io.Copy(os.Stdout, cr) fmt.Println("read", cr.BytesRead(), "bytes")
The adapter pattern in Go is simpler than in Java because Go interfaces are implicit. A wrapper struct that delegates to the original type and has the right method signatures automatically satisfies any compatible interface — no import of the interface's package, no extends Adapter.
More Related questions...