78

I'm writing a game in go. In C++ I would store all my entity classes in an array of the BaseEntity class. If an entity needed to move about in the world it would be a PhysEntity which is derived from a BaseEntity, but with added methods. I tried to imitate this is go:

package main

type Entity interface {
    a() string
}

type PhysEntity interface {
    Entity
    b() string
}

type BaseEntity struct { }
func (e *BaseEntity) a() string { return "Hello " }

type BasePhysEntity struct { BaseEntity }
func (e *BasePhysEntity) b() string { return " World!" }

func main() {
    physEnt := PhysEntity(new(BasePhysEntity))
    entity := Entity(physEnt)
    print(entity.a())
    original := PhysEntity(entity)
// ERROR on line above: cannot convert physEnt (type PhysEntity) to type Entity:
    println(original.b())
}

This will not compile as it cant tell that 'entity' was a PhysEntity. What is a suitable alternative to this method?

2 Answers2

125

Use a type assertion. For example,

original, ok := entity.(PhysEntity)
if ok {
    println(original.b())
}
peterSO
  • 158,998
  • 31
  • 281
  • 276
  • 3
    Do you know if type assertions are expensive to use? Is it worth me keeping track of type with a variable in the BaseEntity? –  Jan 26 '11 at 08:29
  • 7
    type assertions are cheap. – rog Feb 28 '11 at 09:01
  • When I try this, I get an error: `invalid type assertion .. (non-interface type .. on left)` – Zac May 18 '17 at 17:42
  • 1
    @Zac because "type assertion" valid on "interface", your value is not "interface". – khue bui Feb 05 '18 at 07:23
9

Specifically, the Go "interface" type has the information on what the object really was, that was passed by interface, so casting it is much cheaper than a C++ dynamic_cast or the equivalent java test-and-cast.

weregamer
  • 91
  • 1
  • 1