Introduction
- Interfaces are a collection of method signatures.
type shape interface {
area() int
perimeter() int
}
In the above example, shape is anything that can be used to calculate its area and parameter. If you check the example below, you can see that rectangle implements both the area() and perimeter() methods. So, it means rectangle implements the shape interface.
type rectangle struct {
length int
width int
}
func (r rectangle) area() int {
return r.length * r.width
}
func (r rectangle) perimeter() int {
return (r.length + r.width) * 2
}
- Multiple types can implement the same interface. If there is another struct named
circlewitharea()andperimeter()methods, then it also implements theshapeinterface. - Likewise, a single type can implement multiple interfaces as well. For example, an empty interface like
interface {}is always implemented by every type. - In Go, interfaces are implemented implicitly. If you check the above function, you can see that we have never explicitly mentioned that the
rectanglestruct is implemented byshape(like we do in Java).
Named argument interfaces
You can also use named arguments and return data in interface methods. If you check the below function, it is not that clear what are the arguments passing to the Copy() method. You only know that they should be strings.
type Copier interface {
Copy(string, string) int
}
Therefore, to give more readable interface methods, you can define the interface like below.
type Copier interface {
Copy(sourceFile string, destFile string) (copiedBytes int)
}
Type assertion
Assume you have several types implemented by the shape interface. But you need to write a function to take the area of a rectangle. In such a case, you should use type assertion.
func getArea(s shape) int {
r, ok := s.(rectangle)
if ok {
return r.length * r.width
}
return 0
}
Here, you pass a shape and check whether it's a rectangle. If it is, the value of ok would be true. And r would get a rectangle struct.
Type Switch
Instead of type assertion, you can also use switch cases.
func printNumericValue(num interface{}) {
switch v := num.(type) {
case int:
fmt.Printf("%d", v)
case string:
fmt.Printf("%s", v)
default:
fmt.Printf("%T", v)
}
}
Clean Interfaces
- Keep interfaces as simple as you can.
- Don't make the interface aware of the underlying types (ex:
shapeinterface should not have methods likeisCircle()).
Interfaces are not classes. They are much simpler. They don't have constructors or deconstructors to create/destroy data. There is no hierarchy of passing behavior (parent-to-child behavior).
Top comments (0)