Tutorials Logic, IN info@tutorialslogic.com

Golang Interfaces: Implicit Contracts and Polymorphism

Implicit Implementation

A Go interface describes behavior through method signatures. A type satisfies an interface automatically when it has the required methods; there is no `implements` keyword.

Interfaces are most powerful when they are small and placed near the code that consumes the behavior. Instead of designing large inheritance trees, Go programs often define tiny interfaces such as `io.Reader`, `io.Writer`, `Stringer`, `Store`, or `Notifier`.

A concrete type does not need to declare that it implements an interface. If the method set matches, it works. This makes Go interfaces flexible and easy to introduce around existing types.

  • Interfaces define what a value can do, not what it is.
  • A type can satisfy many interfaces at the same time.
  • Small interfaces are easier to test and reuse.
  • Accept interfaces in functions when you need behavior, return concrete types when possible.

Small Interface

Small Interface
package main

import "fmt"

type Notifier interface {
	Notify(message string) error
}

type EmailNotifier struct {
	Address string
}

func (e EmailNotifier) Notify(message string) error {
	fmt.Println("email to", e.Address+":", message)
	return nil
}

func SendWelcome(n Notifier) error {
	return n.Notify("Welcome to Go interfaces")
}

func main() {
	notifier := EmailNotifier{Address: "student@example.com"}
	_ = SendWelcome(notifier)
}

Type Assertions and Type Switches

Sometimes an interface value must be inspected to find its concrete type. Use type assertions carefully and prefer the comma-ok form to avoid panics.

  • Use `value, ok := x.(SomeType)` for safe type assertions.
  • Use a type switch when several concrete types need different handling.
  • Avoid using `interface{}` or `any` when a specific interface would be clearer.

Testing with Interfaces

Interfaces are useful for tests because you can replace a real dependency with a fake. For example, a service can depend on a small `UserStore` interface instead of a real database client.

  • Define interfaces around behavior your code needs.
  • Keep test fakes small and predictable.
  • Do not create interfaces too early when there is only one concrete type and no testing benefit.

Interface for Storage

Interface for Storage
type User struct {
	ID    int
	Email string
}

type UserStore interface {
	FindByID(id int) (User, error)
}

type UserService struct {
	store UserStore
}

func (s UserService) EmailForUser(id int) (string, error) {
	user, err := s.store.FindByID(id)
	if err != nil {
		return "", err
	}
	return user.Email, nil
}
Before you move on

Golang Interfaces: Implicit Contracts and Polymorphism Mastery Check

5 checks
  • A concrete type does not need to declare that it implements an interface.
  • If the method set matches, it works.
  • This makes Go interfaces flexible and easy to introduce around existing types.
  • Sometimes an interface value must be inspected to find its concrete type.
  • Use type assertions carefully and prefer the comma-ok form to avoid panics.

Golang Interfaces Questions Learners Ask

Go uses structural typing for interfaces. If a type has the required methods, it satisfies the interface automatically.

Often with the consumer. The consumer knows the behavior it needs.

An interface value stores both a dynamic type and a dynamic value. If the dynamic type is *User but the value is nil, the interface itself is not nil because it still has type information.

Next Step
Next Practice

Finish the concept here, then reinforce it with hands-on coding, interview prep, or a tool that matches the topic.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.