Accessing the underlying struct of an interface
Converting between an interface
and a struct
can be done leveraging type assertions in Go. Let’s take the following example code and see how it would work:
package main
import (
"fmt"
"math"
)
type shape interface {
area() float64
}
type rectangle struct {
length float64
width float64
}
type circle struct {
radius float64
}
func (r rectangle) area() float64 {
return r.length * r.width
}
func (c circle) area() float64 {
return math.Pi * math.Pow(c.radius, 2)
}
func main() {
// Create a slice of shapes to iterate over
shapes := []shape{
rectangle{length: 2, width: 2},
circle{radius: 3},
}
for _, item := range shapes {
if rect, ok := item.(rectangle); ok {
// Check if the item is a rectangle, if it is, then enter this if block
fmt.Println("I'm a rectangle")
fmt.Printf("length: %f, width %f, area: %f\n", rect.length, rect.width, item.area())
} else if circ, ok := item.(circle); ok {
// Check if the item is a cirlce, if it is, then enter this if block
fmt.Println("I'm a circle")
fmt.Printf("radius: %f, area: %f\n", circ.radius, item.area())
} else {
// If it's anything else, we aren't sure what it is
fmt.Println("I don't know what I am")
}
}
}
When running this code you should see the following output:
I'm a rectangle
length: 2.000000, width 2.000000, area: 4.000000
I'm a circle
radius: 3.000000, area: 28.274334
As you can see in the above example you can leverage type assertions to get access to the underlying data of an object. This can be extremely useful for things like custom errors, where you might have additional information, like what HTTP status code to return, or more detailed information on the error.