Explicit type requires a formal declaration to implement an interface and implicit type satisfies an interface automatically by implementing its methods without declaration.
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.
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.
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.
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 Shape
using Area()
and Perimeter()
.
We create two types, Circle
and Rectangle
.
Both Circle
and Rectangle
have methods Area()
and Perimeter()
with the same signatures as those declared in the Shape
interface.
Since both types provide implementations for all the methods of the Shape
interface, they are considered to implicitly satisfy the interface.
The PrintShapeInfo
function takes any type that satisfies the Shape
interface and prints its area and perimeter.
In the main
function, we create instances of Circle
and Rectangle
and pass them to PrintShapeInfo
, demonstrating how different types satisfying the same interface can be used interchangeably.
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)}
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.
Haven’t found what you were looking for? Contact Us
Free Resources