In Go, interfaces are a powerful tool for creating flexible and extensible code. One of the benefits of interfaces is that they allow us to write code that works with any type that satisfies the interface, without having to know the concrete type of the object at compile time. However, sometimes we need to check at runtime whether a given type satisfies an interface or not. In this article, we’ll explore how to do that in Go.
The interface type assertion
Before we dive into checking whether a type satisfies an interface, let’s briefly review how to assert that a value implements an interface in Go. Go provides a special syntax for type assertions that allows us to check if a value is of a certain interface type, and if so, obtain its underlying value of that type. Here’s the basic syntax:
value, ok := object.(InterfaceType)
Here, object
is the value we want to check, InterfaceType
is the interface type we want to assert, value
is a variable that will hold the underlying value of object
if it implements InterfaceType
, and ok
is a boolean variable that will be set to true
if the assertion succeeds, and false
otherwise.
For example, suppose we have the following interface:
type Reader interface {
Read(p []byte) (n int, err error)
}
We can use a type assertion to check if a value obj
implements the Reader
interface as follows:
if r, ok := obj.(Reader); ok {
// obj implements the Reader interface, and r is the underlying value of type Reader
// do something with r...
} else {
// obj does not implement the Reader interface
}
Using reflection
Now that we know how to assert that a value implements an interface, let’s see how to check if a type satisfies an interface at runtime. In Go, we can check if a type T
satisfies an interface I
by checking if T
implements all the methods of I
. To do this, we can use the reflect
package, which provides a set of functions and types for working with Go’s reflection API.
The reflect.Type
interface represents a Go type, and provides a method called Implements
that allows us to check if a type implements another type or interface. Here’s the basic syntax:
type T struct {...}
type I interface {...}
t := reflect.TypeOf(T{})
i := reflect.TypeOf((*I)(nil)).Elem()
if t.Implements(i) {
// T implements the interface I
} else {
// T does not implement the interface I
}
Here, we define a type T
and an interface I
. We then create a reflect.Type
value t
that represents the type T
, and an interface{}
value i
that represents the interface I
. We use the Elem
method of reflect.Type
to obtain the type of the interface value (which is I
in this case).
We can then call the Implements
method of t
to check if T
implements I
. If it does, the method returns true
, and if not, it returns false
.
Conclusion
In this article, we’ve seen how to check if a type satisfies an interface at runtime in Go. By using type assertion and the reflect
package, we can check if a type implements an interface by checking if it implements all the methods of the interface. This allows us to write flexible and extensible code that works with any type that satisfies an interface. From the two approach above I prefer to use assertion type instead of using reflection.