Introduction
Interfaces in Go are a way to define a set of methods that a type must implement. They provide a way to specify the behavior that types must satisfy, allowing for more flexible and decoupled code. In this chapter, you will learn the basics of defining, implementing, and using interfaces in Go, with examples to illustrate their usage.
Defining an Interface
An interface is defined using the type
keyword, followed by the name of the interface and the interface
keyword. The methods that the interface requires are listed within curly braces {}
.
Syntax:
type InterfaceName interface {
Method1(params) returnType
Method2(params) returnType
...
}
Example
Example:
package main
import "fmt"
// Defining an interface
type Speaker interface {
Speak() string
}
// Implementing the interface in a struct
type Person struct {
Name string
}
func (p Person) Speak() string {
return "Hello, my name is " + p.Name
}
func main() {
var s Speaker
p := Person{Name: "Alice"}
s = p
fmt.Println(s.Speak()) // Output: Hello, my name is Alice
}
Implementing an Interface
A type implements an interface by defining all the methods listed in the interface. There is no explicit declaration required to implement an interface; it is implicit.
Example: Multiple Implementations
Example:
package main
import "fmt"
// Defining an interface
type Speaker interface {
Speak() string
}
// Implementing the interface in a struct
type Person struct {
Name string
}
func (p Person) Speak() string {
return "Hello, my name is " + p.Name
}
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return "Woof! I am " + d.Name
}
func main() {
var speakers []Speaker
p := Person{Name: "Bob"}
d := Dog{Name: "Rex"}
speakers = append(speakers, p, d)
for _, s := range speakers {
fmt.Println(s.Speak())
}
// Output:
// Hello, my name is Bob
// Woof! I am Rex
}
Using Interfaces
Interfaces allow you to write functions that can accept any type that implements a specific interface.
Example: Function with Interface Parameter
Example:
package main
import "fmt"
// Defining an interface
type Speaker interface {
Speak() string
}
type Person struct {
Name string
}
func (p Person) Speak() string {
return "Hello, my name is " + p.Name
}
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return "Woof! I am " + d.Name
}
// Function that accepts any Speaker
func Greet(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
p := Person{Name: "Charlie"}
d := Dog{Name: "Buddy"}
Greet(p) // Output: Hello, my name is Charlie
Greet(d) // Output: Woof! I am Buddy
}
Empty Interface
The empty interface (interface{}
) is a special type that can hold any value, as every type implements at least zero methods.
Example: Using Empty Interface
Example:
package main
import "fmt"
func PrintAnyType(val interface{}) {
fmt.Println(val)
}
func main() {
PrintAnyType("Hello, World!") // Output: Hello, World!
PrintAnyType(42) // Output: 42
PrintAnyType(true) // Output: true
}
Type Assertion
Type assertion allows you to retrieve the underlying value of an interface. It is used to convert an interface to a specific type.
Example: Using Type Assertion
Example:
package main
import "fmt"
func main() {
var val interface{} = "Hello, Go!"
str, ok := val.(string)
if ok {
fmt.Println("String value:", str) // Output: String value: Hello, Go!
} else {
fmt.Println("Not a string")
}
num, ok := val.(int)
if ok {
fmt.Println("Integer value:", num)
} else {
fmt.Println("Not an integer") // Output: Not an integer
}
}
Type Switch
A type switch is a construct that allows you to switch on the type of an interface value.
Example: Using Type Switch
Example:
package main
import "fmt"
func Describe(val interface{}) {
switch v := val.(type) {
case string:
fmt.Println("String value:", v)
case int:
fmt.Println("Integer value:", v)
default:
fmt.Println("Unknown type")
}
}
func main() {
Describe("Hello, Go!") // Output: String value: Hello, Go!
Describe(42) // Output: Integer value: 42
Describe(true) // Output: Unknown type
}
Conclusion
Interfaces in Go provide a powerful way to define and use abstractions. They allow for more flexible and decoupled code by specifying the behavior that types must satisfy. By understanding how to define, implement, and use interfaces, you can create more modular and reusable Go programs. Interfaces, combined with type assertions and type switches, enable you to handle different types in a generic and type-safe manner.