Explicit type requires a formal declaration to implement an interface and implicit type satisfies an interface automatically by implementing its methods without declaration.
How are interfaces implicitly satisfied in Go
Key takeaways:
Interfaces define a set of methods that a type must implement.
A type satisfies an interface implicitly by having the required methods, without needing an explicit declaration. This feature enhances flexibility, decouples components, and simplifies code.
Interfaces allow for polymorphism, making it easy to write generic functions.
Understanding and using interfaces effectively is crucial for Go developers to create maintainable and scalable applications.
Go is known for its simplicity and powerful features, one of which is its approach to interfaces. Unlike many programming languages, Go allows types to satisfy interfaces implicitly.
Implicit satisfaction of Interfaces
In Go, an interface is a type that specifies a set of method signatures. It is a way to define a contract for types, stating which methods they must implement. Unlike some other languages, Go interfaces are implicit, meaning a type automatically satisfies an interface if it implements the required methods without requiring explicit declarations.
Usage
Interfaces are declared using the type keyword followed by the interface name, interface keyword, and a set of method signatures inside curly braces.
type MyInterface interface {Method1() intMethod2() string}
In Go, interfaces are implicitly satisfied based on the method set of a type. A type is considered to implement an interface if it provides implementations for all the methods declared by that interface.
Example of implicit satisfaction
Let’s walk through an example to illustrate how interfaces are implicitly satisfied in Go:
package mainimport "fmt"// Defining an interface named Shapetype Shape interface {Area() float64Perimeter() float64}// Defining a type named Circletype Circle struct {Radius float64}// Implementing the methods for Circle to satisfy the Shape interfacefunc (c Circle) Area() float64 {return 3.14 * c.Radius * c.Radius}func (c Circle) Perimeter() float64 {return 2 * 3.14 * c.Radius}// Defining a type named Rectangletype Rectangle struct {Length float64Width float64}// Implementing the methods for Rectangle to satisfy the Shape interfacefunc (r Rectangle) Area() float64 {return r.Length * r.Width}func (r Rectangle) Perimeter() float64 {return 2*r.Length + 2*r.Width}// Function that takes any Shape and prints its Area and Perimeterfunc PrintShapeInfo(s Shape) {fmt.Printf("Area: %f, Perimeter: %f\n", s.Area(), s.Perimeter())}func main() {// Creating a Circle and a Rectanglecircle := Circle{Radius: 5}rectangle := Rectangle{Length: 4, Width: 6}// Implicitly satisfying the Shape interface// Both Circle and Rectangle types can be used wherever Shape is expectedPrintShapeInfo(circle)PrintShapeInfo(rectangle)}
Let’s now look at the code explanation step by step:
We define an interface called
ShapeusingArea()andPerimeter().We create two types,
CircleandRectangle.Both
CircleandRectanglehave methodsArea()andPerimeter()with the same signatures as those declared in theShapeinterface.Since both types provide implementations for all the methods of the
Shapeinterface, they are considered to implicitly satisfy the interface.The
PrintShapeInfofunction takes any type that satisfies theShapeinterface and prints its area and perimeter.In the
mainfunction, we create instances ofCircleandRectangleand pass them toPrintShapeInfo, demonstrating how different types satisfying the same interface can be used interchangeably.
Implementing multiple interfaces
A type can satisfy multiple interfaces, allowing for rich behavior definition:
package mainimport "fmt"// Defining an interface named Shapetype Shape interface {Area() float64}// Defining an interface named Coloredtype Colored interface {Color() string}// Defining a type named Circletype Circle struct {Radius float64ColorName string // New field for color}// Implementing the methods for Circle to satisfy the Shape interfacefunc (c Circle) Area() float64 {return 3.14 * c.Radius * c.Radius}// Implementing the Color method for Circle to satisfy the Colored interfacefunc (c Circle) Color() string {return c.ColorName}// Function that takes Shape and prints its Areafunc PrintShapeInfo(s Shape) {fmt.Printf("Area: %f\n", s.Area())}// Function that takes Colored shape and prints its colorfunc PrintShapeColor(c Colored) {fmt.Printf("Color: %s\n", c.Color())}func main() {// Creating a Circle and a Rectanglecircle := Circle{Radius: 5, ColorName: "Red"}// Implicitly satisfying the Shape interfacePrintShapeInfo(circle)// Implicitly satisfying the Colored interfacePrintShapeColor(circle)}
Advantages of implicit interface
The following are some of the advantages of the implicit interface:
Easily swap types that implement the same interface, adapting to changing requirements.
Promote cleaner code by allowing functions to operate on various types without specifics.
Maintain a clean codebase without explicit declarations, focusing on behavior.
Create mock types for straightforward testing without altering original implementations.
Frequently asked questions
Haven’t found what you were looking for? Contact Us
What is the difference between explicit and implicit type?
What is type assertions in Go?
What is the difference between interfaces and structs in Go?
Free Resources