Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. Go Dictionary
  3. interface

interface

Since: Go 1.0(2012)

An interface defines a set of methods that a type must implement. In Go, interfaces are implemented implicitly — no explicit declaration is required.

Syntax

type InterfaceName interface {
    MethodName(params) ReturnType
}

// The empty interface (any) accepts all types.
var v any = "Hello"
var v interface{} = 42

Interface overview

Syntax / TypeDescription
type I interface { M() }Defines an interface that requires the method M().
anyA built-in alias for interface{} (Go 1.18+). Accepts all types.
interface{}An empty interface with zero methods. Every type satisfies it.
Type assertion: v.(T)Converts an interface value to a concrete type. Panics if the conversion fails.
Type assertion: v, ok := v.(T)A safe form of type assertion. If the conversion fails, ok is false and no panic occurs.
Type switch: switch v.(type)Branches execution based on the concrete type of an interface value.

Sample code

interface.go
package main

import (
    "fmt"
    "math"
)

// Define the Shape interface.
type Shape interface {
    Area() float64
    Perimeter() float64
}

type Circle struct {
    Radius float64
}

// Circle implicitly implements the Shape interface.
func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

func (c Circle) Perimeter() float64 {
    return 2 * math.Pi * c.Radius
}

type Rectangle struct {
    Width, Height float64
}

// Rectangle also implements the Shape interface.
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

// A function that accepts the Shape interface as a parameter.
func printShape(s Shape) {
    fmt.Printf("Area: %.2f, Perimeter: %.2f\n", s.Area(), s.Perimeter())
}

func main() {
    c := Circle{Radius: 5}
    r := Rectangle{Width: 3, Height: 4}

    printShape(c) // Circle satisfies Shape.
    printShape(r) // Rectangle also satisfies Shape.

    // The empty interface accepts all types.
    var anything any = "hello"
    fmt.Println(anything) // Prints "hello".
    anything = 123
    fmt.Println(anything) // Prints "123".

    // Use a type assertion to convert to a concrete type.
    var s Shape = Circle{Radius: 3}
    if circle, ok := s.(Circle); ok {
        fmt.Println("Radius:", circle.Radius) // Prints "Radius: 3".
    }

    // Use a type switch to branch by type.
    values := []any{42, "hello", true, 3.14}
    for _, v := range values {
        switch val := v.(type) {
        case int:
            fmt.Printf("int: %d\n", val)
        case string:
            fmt.Printf("string: %s\n", val)
        default:
            fmt.Printf("other: %v\n", val)
        }
    }
}

This produces the following output:

go run interface.go
Area: 78.54, Perimeter: 31.42
Area: 12.00, Perimeter: 14.00
hello
123
Radius: 3
int: 42
string: hello
other: true
other: 3.14

How implicit implementation works

Go interfaces are implemented implicitly. Unlike Java or Kotlin, you never write implements InterfaceName. A type automatically satisfies an interface simply by defining all the methods it requires. This is called "duck typing."

This design lets you define an interface and its implementations in separate packages. You can also retrofit an existing type to satisfy an interface you define later.

sample_implicit_interface.go
package main

import "fmt"

// Stringer interface (the fmt package defines a similar one)
type Stringer interface {
    String() string
}

// This struct does not need to mention Stringer when it is defined
type Character struct {
    Name  string
    Power int
}

// Defining String() automatically satisfies the Stringer interface
func (c Character) String() string {
    return fmt.Sprintf("%s (Power: %d)", c.Name, c.Power)
}

// Accepts anything that satisfies Stringer
func printAll(items []Stringer) {
    for _, item := range items {
        fmt.Println(item.String())
    }
}

// A common idiom to verify interface satisfaction at compile time
// var _ Stringer = Character{} // Compile error if Character does not satisfy Stringer

func main() {
    chars := []Stringer{
        Character{Name: "Kiryu Kazuma", Power: 95},
        Character{Name: "Majima Goro", Power: 92},
    }
    printAll(chars)
}

This produces the following output:

go run sample_implicit_interface.go
Kiryu Kazuma (Power: 95)
Majima Goro (Power: 92)

Pitfalls of the empty interface

The empty interface (any / interface{}) accepts every type, but overusing it erodes type safety. Defining a specific interface where possible keeps your code more robust.

Less ideal: accepts anything but loses type information.

sample_any_bad.go
package main

import "fmt"

func printAnything(v any) {
    fmt.Printf("value: %v, type: %T\n", v, v)
}

func main() {
    var v any = "Kiryu"
    if s, ok := v.(string); ok {
        fmt.Println("string:", s)
    }

    if n, ok := v.(int); ok {
        fmt.Println("int:", n)
    } else {
        fmt.Println("not an int")
    }
}

This produces the following output:

go run sample_any_bad.go
string: Kiryu
not an int

Better: Define an interface that requires only the methods you need.

sample_any_interface.go
package main

import "fmt"

type Displayable interface {
    Display() string
}

type Item struct {
    Name  string
    Price int
}

func (it Item) Display() string {
    return fmt.Sprintf("%s: $%d", it.Name, it.Price)
}

func printDisplayable(d Displayable) {
    fmt.Println(d.Display())
}

func main() {
    printDisplayable(Item{Name: "Kiryu's Suit", Price: 500})
}

This produces the following output:

go run sample_any_interface.go
Kiryu's Suit: $500

Common Mistakes

Common mistake 1: pointer receiver constraint

A method defined with a pointer receiver cannot be satisfied by a value type. Only the pointer type satisfies the interface.

package main

type Animal interface {
    Sound() string
}

type Cat struct{ Name string }

// Pointer receiver: *Cat satisfies Animal, but Cat does not
func (c *Cat) Sound() string { return "Meow" }

func makeSound(a Animal) {}

func main() {
    // makeSound(Cat{Name: "Tama"}) // Compile error: Cat does not satisfy Animal
}

OK: Pass a pointer to satisfy the interface.

sample_interface_ok.go
package main

import "fmt"

type Animal interface {
    Sound() string
}

type Dog struct{ Name string }

func (d Dog) Sound() string { return "Woof" }

type Cat struct{ Name string }

func (c *Cat) Sound() string { return "Meow" }

func makeSound(a Animal) {
    fmt.Println(a.Sound())
}

func main() {
    // Dog uses a value receiver, so both Dog and *Dog satisfy Animal
    makeSound(Dog{Name: "Hachiko"})

    // Cat uses a pointer receiver, so only *Cat satisfies Animal
    makeSound(&Cat{Name: "Tama"}) // pass a pointer
}

This produces the following output:

go run sample_interface_ok.go
Woof
Meow

Common mistake 2: nil interface pitfall

A nil interface and an interface holding a nil pointer are not the same. An interface variable that stores a typed nil pointer is not nil itself.

sample_interface_nil.go
package main

import "fmt"

type Animal interface {
    Sound() string
}

type Dog struct{ Name string }

func (d *Dog) Sound() string { return "Woof" }

func main() {
    var a Animal = nil // The interface itself is nil
    var d *Dog = nil // A nil pointer — still has type information
    var a2 Animal = d // An interface holding a nil pointer

    fmt.Println(a == nil) // true:  a is a true nil interface
    fmt.Println(a2 == nil) // false: a2 carries type info, so it is NOT nil!
}

This produces the following output:

go run sample_interface_nil.go
true
false

Notes

Unlike many other languages, Go does not require a type to explicitly declare that it implements an interface. If a type implements all the methods an interface requires, it satisfies that interface automatically. This is known as "duck typing" — a mechanism where a type is considered to satisfy an interface simply by having the required methods, without any explicit declaration.

The type assertion v.(T) panics if the conversion fails. To convert safely, use the two-value form v, ok := v.(T).

The empty interface any (formerly interface{}) can hold any type, but you must use a type assertion or type switch to work with the underlying value. Defining a specific interface rather than relying on any keeps your code type-safe.

If you find any errors or copyright issues, please .