More on interfaces
We discovered the magic of interfaces in the previous chapter, how a simple concept as defining a type's behavior can offer tremendous opportunities.
If you haven't read the previous chapter, you shouldn't read this one, simply because most of what we're about to study depends on a good understanding of the previous chapter.
Shall we begin?
Knowing what is stored in a interface variable
We know that a variable of a given interface can store any value of any type that implements this interface. That's the good part, but what if we wanted to retrieve a value stored in an interface variable and put it in a regular type variable, how do we know what exact type was "wrapped" in that interface variable?
Let's see an example to clarify the actual question:
So, the question confronting us is:
How do we test the type that is stored in an interface variable?
Comma-ok type assertions
Go comes with a handy syntax to know whether it is possible to convert an
interface value to a given type value, it's as easy as this:
value, ok =
value is a variable of type
ok is a boolean,
element is the interface variable.
If it is possible to convert
element to type
ok is set to
value is set to the result of this conversion.
ok is set to
value is set to the zero value
Let's use this comma-ok type assertion in an example:
It's that simple!
Notice the syntax we used with our
ifs? I hope that you still remember that
you can initialize inside an
if! Do you??
Yes, I know, the more we test for other types, the more the
chain gets harder to read. And this is why they invented the type switch!
The type switch test
Better to show it off with an example, right? Ok, let's rewrite the previous example. Here we Go!
Now repeat after me:
element.(type)construct SHOULD NOT be used outside of a switch statement! -- Can you use it elsewhere? -- NO, YOU CAN NOT!"
If you need to make a single test, use the comma-ok test.
Just DON'T use
element.(type) outside of a switch statement.
What's really nice with Go is the logic side of its syntax. When we learnt
about anonymous fields in
structs we found it quite natural, didn't we?
Now, by applying the same logic, wouldn't it be nice to be able to embed an
interface1 within another interface
interface2 so that
interface2 "inherits" the methods in
I say "logic", because after all: interfaces are sets of methods, just like structs are sets of fields. And so it is! In Go you can put an interface type into another.
Example: Suppose that you have an indexed collections of elements, and that you want to get the minimum, and the maximum value of this collection without changing the elements order in this collection.
One silly but illustrative way to do this is by using the
saw in the previous chapter. But then again, the function
by the sort package actually changes the input collection!
We add two methods:
The example is idiotic (the opposite of idiomatic!) but it did work as desired. Mind you, interface embedding can be very useful, you can find some interface embedding in some Go packages as well. For example, the container/heap package that provides heap operations of data collections that implement this interface:
Types that implement io.ReadWriter can read and write since they implement both Reader and Writer interfaces.
Did I mention yet to make sure you never use
element.(type) outside of a