Interfaces

Define and implement interfaces for polymorphism in Go

#interfaces #polymorphism #methods #types

Interfaces

Interfaces define behavior through method signatures in Go.

Basic Interface

package main

import "fmt"

type Shape interface {
    Area() float64
}

type Rectangle struct {
    width, height float64
}

func (r Rectangle) Area() float64 {
    return r.width * r.height
}

func main() {
    var s Shape
    s = Rectangle{width: 10, height: 5}
    fmt.Println("Area:", s.Area())  // 50
}

Multiple Implementations

type Circle struct {
    radius float64
}

func (c Circle) Area() float64 {
    return 3.14159 * c.radius * c.radius
}

func printArea(s Shape) {
    fmt.Printf("Area: %.2f\n", s.Area())
}

func main() {
    rect := Rectangle{10, 5}
    circle := Circle{7}

    printArea(rect)    // Area: 50.00
    printArea(circle)  // Area: 153.94
}

Interface with Multiple Methods

type Geometry interface {
    Area() float64
    Perimeter() float64
}

type Rectangle struct {
    width, height float64
}

func (r Rectangle) Area() float64 {
    return r.width * r.height
}

func (r Rectangle) Perimeter() float64 {
    return 2*r.width + 2*r.height
}

func measure(g Geometry) {
    fmt.Println("Area:", g.Area())
    fmt.Println("Perimeter:", g.Perimeter())
}

Empty Interface

func describe(i interface{}) {
    fmt.Printf("Type: %T, Value: %v\n", i, i)
}

func main() {
    describe(42)           // Type: int, Value: 42
    describe("hello")      // Type: string, Value: hello
    describe(true)         // Type: bool, Value: true
    describe([]int{1, 2})  // Type: []int, Value: [1 2]
}

Type Assertions

func main() {
    var i interface{} = "hello"

    // Type assertion
    s := i.(string)
    fmt.Println(s)  // hello

    // Type assertion with check
    s, ok := i.(string)
    if ok {
        fmt.Println("String:", s)
    }

    // This would panic without check
    // f := i.(float64)
    f, ok := i.(float64)
    fmt.Println("Float:", f, "OK:", ok)  // Float: 0 OK: false
}

Type Switch

func do(i interface{}) {
    switch v := i.(type) {
    case int:
        fmt.Printf("Integer: %d\n", v)
    case string:
        fmt.Printf("String: %s\n", v)
    case bool:
        fmt.Printf("Boolean: %t\n", v)
    default:
        fmt.Printf("Unknown type: %T\n", v)
    }
}

func main() {
    do(21)       // Integer: 21
    do("hello")  // String: hello
    do(true)     // Boolean: true
    do(3.14)     // Unknown type: float64
}

Interface Composition

type Reader interface {
    Read() string
}

type Writer interface {
    Write(s string)
}

// Composed interface
type ReadWriter interface {
    Reader
    Writer
}

type File struct {
    content string
}

func (f *File) Read() string {
    return f.content
}

func (f *File) Write(s string) {
    f.content = s
}

func main() {
    var rw ReadWriter = &File{}
    rw.Write("Hello, Go!")
    fmt.Println(rw.Read())  // Hello, Go!
}

Stringer Interface

import "fmt"

type Person struct {
    Name string
    Age  int
}

// Implement fmt.Stringer interface
func (p Person) String() string {
    return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}

func main() {
    p := Person{"Alice", 30}
    fmt.Println(p)  // Alice (30 years old)
}

Error Interface

type MyError struct {
    Message string
    Code    int
}

func (e MyError) Error() string {
    return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}

func doSomething() error {
    return MyError{"Something went wrong", 500}
}

func main() {
    err := doSomething()
    if err != null {
        fmt.Println(err)  // Error 500: Something went wrong
    }
}

Interface Values

type I interface {
    M()
}

type T struct {
    S string
}

func (t *T) M() {
    if t == nil {
        fmt.Println("<nil>")
        return
    }
    fmt.Println(t.S)
}

func main() {
    var i I

    // nil interface
    // i.M()  // Would panic

    var t *T
    i = t
    i.M()  // <nil> (interface holds nil value)

    i = &T{"hello"}
    i.M()  // hello
}

Practical Example: Logger Interface

type Logger interface {
    Log(message string)
}

type ConsoleLogger struct{}

func (c ConsoleLogger) Log(message string) {
    fmt.Println("[CONSOLE]", message)
}

type FileLogger struct {
    filename string
}

func (f FileLogger) Log(message string) {
    fmt.Printf("[FILE:%s] %s\n", f.filename, message)
}

func process(logger Logger) {
    logger.Log("Processing started")
    // Do work...
    logger.Log("Processing completed")
}

func main() {
    process(ConsoleLogger{})
    process(FileLogger{"app.log"})
}

Discover another handy tool from EditPDF.pro