You can't do that because interface values don't do that.
What interface values do—<em>regardless of the interface type itself; it doesn't matter if the interface type is empty or not—is that they hold two things:
- the concrete type of some value (or no type); and
- the value of that concrete type (or no value).
So if some variable v
or expression e
has type I
where I
is an interface type, then you can, with some syntax, inspect either or both of these two "fields". They're not struct
fields so you can't just use v.type
, but you can do this:
switch v.(type) {
case int: // the value in v has type int
case *float64: // the value in v has type float64
// etc
}
The .(type)
in a switch
means let me look at the type field.
Getting the actual value is harder, because Go more or less requires that you check the type first. In your case, you know that i
holds either a Dog
or a Cat
, so you can write:
var name string
switch i.(type) {
case Dog: name = i.(Dog).name
case Cat: name = i.(Cat).name
default: panic("whatever 'i' is, it is not a Dog or Cat")
}
fmt.Println(name)
This is pretty clumsy, and there are lots of ways to make it less clumsy, but that's always the first step: figure out what the type is.
Well, sometimes there's a step before the first step: figure out whether the variable has anything at all in it. You do this with:
if i == nil {
...
}
Note, however, that if i
has some typed value in it, and the type can hold nil pointers, the value part of i
can be nil and yet i == nil
will be false. That's because i
does have a type in it.
var i interface{}
var p *int
if i == nil {
fmt.Println("i is initially nil")
}
if p == nil {
fmt.Println("p is nil")
}
i = p
if i != nil {
fmt.Printf("i is now not nil, even though i.(*int) is %v\n", i.(*int))
}
(try this on the Go playground).
This usually isn't the right way to use interface
Most often—there are exceptions—we don't even try to look at the type of some interface. Instead, we define an interface that provides methods—functions we can call—that do something we need done. See Burak Serdar's answer in which the interface type has a getName
method. Then, instead of trying to figure out which of some limited set of types someone gave us, we just say:
name := i.getName()
to invoke the getName
method on the underlying concrete value. If i
holds a Dog
, that calls func (Dog) getName() string
, which you'll need to define. If i
holds a Cat
, it calls func (Cat) getName() string
. If you decide to add to your collection a type named Bird
, you can define func (Bird) getName() string
, and so on.
(Usually, the methods would be exported too: GetName
, rather than getName
.)