Golang by Example

Logo

Methods and Interfaces

Go doesn't have classes, but it does have methods. Methods are functions that are associated with a specific type. They allow you to define behavior for your types, similar to how methods work in object-oriented programming languages.


   type Rectangle struct {
       Width  float64
       Height float64
   }

    func (r Rectangle) Area() float64 {
        return r.Width * r.Height
    }

Compare it to the CalculatePerimeter function we created earlier. The Area method is associated with the Rectangle type and can be called on any instance of Rectangle. It's no longer need an explicit parameter to pass the rectangle instance; instead, it uses the input r to access the fields of the rectangle.

Methods is just a function with a special input argument. The input is the instance of the type on which the method is called. It allows you to access the fields and methods of that instance. Besides only accessing value like code above, you can also declare methods on pointer receivers. This is useful when you want to modify the receiver or avoid copying large structs. The syntax is similar, but you use a pointer type for the receiver.

You can also declare methods on non-struct types. Let's demonstrate this with a string type. The strings package in Go provides many methods for manipulating strings already, such as Contains, Index, and ToUpper. You can also define your own methods on the string type if the need arises. The condition is that you need to define a new type based on the string type, and then you can define methods on that new type.

Interfaces

An interface is a type that defines a set of methods. It allows you to specify a contract that types must adhere to. Interfaces are a powerful feature in Go, enabling polymorphism and code reuse. You can define an interface using the interface keyword, followed by a list of method signatures.


   type Shape interface {
       Area() float64
   }

In the code above, we define an interface named Shape with a single method Area. Any type that implements this method can be considered a Shape. This allows you to write functions that accept any type that implements the Shape interface.

The empty interface interface{} is a special case in Go. It can hold values of any type, making it a powerful tool for writing generic code. Since all types implement at least zero methods, the empty interface can be used to accept any value.


   var i interface{}
   i = 42
   i = "Hello"
   i = []int{1, 2, 3}

💡 Quiz
What is the purpose of interfaces in Go?

A value of an interface type can hold any value that implements the methods defined in the interface. This allows you to write functions that can work with different types without knowing their concrete types at compile time.

In the code above, the PrintArea function accepts a parameter of type Shape. This demonstrates polymorphism in Go - the ability to process objects differently depending on their data type or class. Any type that implements the Area method can be passed to this function, regardless of its concrete implementation. The function doesn't need to know whether it's working with a rectangle, circle, or any other shape; it only cares that the object can calculate its area.

This polymorphic behavior allows you to write more flexible, maintainable code that's decoupled from specific implementations. You can add new shapes like triangles or hexagons later without modifying the existing PrintArea function, as long as they implement the Area method. This is a powerful feature for creating extensible systems where components can vary independently.

In Go, interfaces are implemented implicitly - a type automatically satisfies an interface if it has all the required methods. Unlike other languages, Go doesn't use an "implements" keyword or any explicit declaration. This design creates a clean separation between interface definitions and their implementations, allowing types to implement interfaces from any package without prior coordination or planning.

Type Assertion

Type assertion is a way to retrieve the concrete value from an interface. You can use the syntax value, ok := i.(T) to assert that the interface i holds a value of type T. If the assertion is successful, ok will be true, and value will hold the concrete value. If the assertion fails, ok will be false, and value will be the zero value of type T.

Let's stop here!

The concept of interface is a bit tricky. You can read more about it in the Interface Explained by Alex Edwards; a well-known Go developer and educator, and his blog is a great resource for learning Go. You can also check out the Go Blog for more articles and tutorials on Go programming in which you might encounter articles that can help you understand the concept of interface better.


Table of contents

Hello World - Begin with the classic Hello World program
Primitives - Learn about the basic data types in Go
Flow Control - Controlling the flow of your program
Struct - All about struct
Functions - Define and call functions
Methods and Interfaces - Methods and interfaces in Go
Error Handling - Handling errors idiomatically
Concurrency - Goroutines and channels
Anti Patterns - Anti patterns in Go
Libraries - Standard library and third-party libraries
Testing - Writing unit tests with `go test`
Benchmarking - Performance benchmarks
Containerization - Dockerize your Go app
What's Next? - Explore the next steps in your Golang journey


Share to: