Golang Tutorial
Fundamentals
Control Statements
Functions & Methods
Structure
Arrays & Slices
String
Pointers
Interfaces
Concurrency
In Go, interfaces provide a way to specify the behavior of an object. They define a contract that a type must fulfill without prescribing how that behavior is implemented. This tutorial will introduce you to interfaces in Go.
An interface is a type that specifies a set of method signatures. A type is said to implement an interface if it provides definitions for all the methods declared by that interface.
Here's a simple example. Let's declare an interface named Talker
:
type Talker interface { Talk() string }
Any type that has a method Talk() string
implements the Talker
interface.
Consider two struct types, Person
and Robot
:
type Person struct { Name string } func (p Person) Talk() string { return "Hi, my name is " + p.Name } type Robot struct { Model string } func (r Robot) Talk() string { return "I am robot " + r.Model }
Both Person
and Robot
implement the Talker
interface because they both have the Talk()
method.
Now that we have two types that implement the Talker
interface, we can write a function that takes a Talker
as an argument:
func Introduce(t Talker) { fmt.Println(t.Talk()) } // Usage: p := Person{Name: "Alice"} r := Robot{Model: "T-800"} Introduce(p) // Outputs: Hi, my name is Alice Introduce(r) // Outputs: I am robot T-800
Go has a special interface type called the empty interface, interface{}
, which has no methods. This means any type implements the empty interface. It's a way to accept any type as an argument without type constraint.
func Describe(i interface{}) { fmt.Printf("(%v, %T)\n", i, i) } // Usage: Describe(42) // Outputs: (42, int) Describe("hello world") // Outputs: (hello world, string)
You can retrieve the underlying value from an interface using a type assertion.
var i interface{} = "hello" s := i.(string) fmt.Println(s) // Outputs: hello // Safe type assertion with "ok" s, ok := i.(string) if ok { fmt.Println(s) // Outputs: hello } else { fmt.Println("Not a string") }
A type switch is a construct that permits multiple type assertions.
func do(i interface{}) { switch v := i.(type) { case int: fmt.Printf("Twice %v is %v\n", v, v*2) case string: fmt.Printf("%q is %v bytes long\n", v, len(v)) default: fmt.Printf("I don't know about type %T!\n", v) } } // Usage: do(21) // Outputs: Twice 21 is 42 do("hello") // Outputs: "hello" is 5 bytes long do(true) // Outputs: I don't know about type bool!
You can embed multiple interfaces into a single interface, creating a combination of their methods.
type Reader interface { Read() string } type Writer interface { Write(string) } type ReadWriter interface { Reader Writer }
In the example above, any type that wants to satisfy the ReadWriter
interface must implement both Read()
and Write(string)
methods.
Interfaces in Go provide a mechanism to define the behavior of objects.
A type implements an interface by providing methods that match the interface's definition.
You can use interfaces to abstract behavior and design more flexible and modular code.
By understanding and using interfaces effectively, you can harness the power of Go's type system to build robust and maintainable applications.
How to define and use interfaces in Golang:
Description: Introduction to defining and using interfaces in Golang, which define a set of methods that a type must implement.
Code:
package main import "fmt" // Define an interface type Shape interface { Area() float64 } // Implement the interface for a specific type (Circle) type Circle struct { Radius float64 } func (c Circle) Area() float64 { return 3.14 * c.Radius * c.Radius } func printArea(s Shape) { fmt.Println("Area:", s.Area()) } func main() { circle := Circle{Radius: 5} printArea(circle) }
Implementing interfaces in Golang examples:
Description: Examples of implementing interfaces for different types, showcasing how each type satisfies the interface.
Code:
package main import "fmt" // Interface type Writer interface { Write([]byte) (int, error) } // Implement interface for a struct (FileWriter) type FileWriter struct { FileName string } func (fw FileWriter) Write(data []byte) (int, error) { // Implementation for writing to a file return len(data), nil } // Implement interface for a different struct (ConsoleWriter) type ConsoleWriter struct{} func (cw ConsoleWriter) Write(data []byte) (int, error) { // Implementation for writing to the console return len(data), nil } func main() { fileWriter := FileWriter{FileName: "example.txt"} consoleWriter := ConsoleWriter{} // Using the interface in a function writeData(fileWriter, []byte("Hello, File!")) writeData(consoleWriter, []byte("Hello, Console!")) } // Function using the interface func writeData(w Writer, data []byte) { w.Write(data) }
Polymorphism with interfaces in Golang:
Description: Demonstrating polymorphism in Golang through interfaces, where different types can be treated uniformly.
Code:
package main import "fmt" // Interface type Speaker interface { Speak() string } // Implement interface for different types (Dog and Cat) type Dog struct{} func (d Dog) Speak() string { return "Woof!" } type Cat struct{} func (c Cat) Speak() string { return "Meow!" } // Function using the interface func makeSound(speaker Speaker) { fmt.Println(speaker.Speak()) } func main() { dog := Dog{} cat := Cat{} makeSound(dog) makeSound(cat) }
Interface composition in Golang:
Description: Combining multiple interfaces into a new interface, allowing a type to satisfy multiple interfaces.
Code:
package main import "fmt" // Interface 1 type Reader interface { Read() string } // Interface 2 type Writer interface { Write(string) error } // Combined interface type ReadWriter interface { Reader Writer } // Struct implementing the combined interface type FileReaderWriter struct { Data string } func (frw FileReaderWriter) Read() string { return frw.Data } func (frw *FileReaderWriter) Write(data string) error { frw.Data = data return nil } func main() { fileReaderWriter := FileReaderWriter{Data: "Hello, File!"} // Using the combined interface fmt.Println("Read:", fileReaderWriter.Read()) fileReaderWriter.Write("Updated content") fmt.Println("Updated Read:", fileReaderWriter.Read()) }
Empty interfaces in Golang and their use cases:
Description: Introduction to empty interfaces (interface{}
) and their use cases, allowing a variable to hold values of any type.
Code:
package main import "fmt" // Function accepting empty interface func printValue(value interface{}) { fmt.Println("Value:", value) } func main() { // Using empty interface to hold values of different types printValue(42) printValue("Hello, Golang!") printValue(3.14) }
Type assertions and type switches with Golang interfaces:
Description: Using type assertions and type switches to work with values stored in empty interfaces.
Code:
package main import "fmt" // Function using type assertion func printTypeAssertion(value interface{}) { if str, ok := value.(string); ok { fmt.Println("String:", str) } else if num, ok := value.(int); ok { fmt.Println("Number:", num) } } // Function using type switch func printTypeSwitch(value interface{}) { switch v := value.(type) { case string: fmt.Println("String:", v) case int: fmt.Println("Number:", v) } } func main() { // Using type assertion printTypeAssertion("Hello, Golang!") printTypeAssertion(42) // Using type switch printTypeSwitch("Hello, Golang!") printTypeSwitch(42) }
Design patterns using interfaces in Golang:
Description: Applying design patterns, such as the Strategy pattern, using interfaces in Golang for flexible behavior.
Code:
package main import "fmt" // Interface for the strategy type PaymentStrategy interface { Pay(amount float64) } // Concrete implementations of the strategy type CreditCardPayment struct{} func (cc CreditCardPayment) Pay(amount float64) { fmt.Printf("Paid $%.2f via Credit Card\n", amount) } type PayPalPayment struct{} func (pp PayPalPayment) Pay(amount float64) { fmt.Printf("Paid $%.2f via PayPal\n", amount) } // Context using the strategy type ShoppingCart struct { PaymentMethod PaymentStrategy } func (sc *ShoppingCart) Checkout(amount float64) { sc.PaymentMethod.Pay(amount) } func main() { creditCardPayment := CreditCardPayment{} payPalPayment := PayPalPayment{} // Using the strategy pattern shoppingCart1 := ShoppingCart{PaymentMethod: creditCardPayment} shoppingCart1.Checkout(100.0) shoppingCart2 := ShoppingCart{PaymentMethod: payPalPayment} shoppingCart2.Checkout(50.0) }
Golang interfaces vs abstract classes in other languages:
Description: Comparing Golang interfaces with abstract classes in other languages, emphasizing the flexibility and simplicity of Golang interfaces.
Code:
package main import "fmt" // Interface defining a method type Speaker interface { Speak() } // Concrete type implementing the interface type Dog struct{} func (d Dog) Speak() { fmt.Println("Woof!") } func main() { dog := Dog{} // Using the interface var speaker Speaker = dog speaker.Speak() }