tworabbits
tworabbits

Reputation: 1213

Golang type assertion / cast to intermediate struct

Given the following types:

type Event interface{}

type ActionResultEvent struct {
    Result string
}

type ActionSuccessEvent ActionResultEvent
type ActionFailureEvent ActionResultEvent

type eventHandleFunc func(e Event)

My goal is to have event handlers (of type eventHandleFunc) for the concrete types ActionSuccessEvent, ActionFailureEvent, as well as for the more abstract ActionResultEvent. The latter I would like to use for both ActionSuccessEvents and ActionFailureEvents.

Now my idea was to just type cast the Event interface to the structure I would like to work on and that works nicely for the concrete types.

// Working perfectly fine
func(e Event) {
  event := e.(ActionFailureEvent)
  fmt.Println(event.Result)
} (ActionFailureEvent{ Result: "failure" })

func(e Event) {
  event := e.(ActionSuccessEvent)
  fmt.Println(event.Result)
} (ActionSuccessEvent{ Result: "success" }) 

Now what about handlers accepting ActionResultEvents? My absolute favourite would look like this one:

func(e Event) {
  event := e.(ActionResultEvent)
  fmt.Println(event.Result)
} (ActionSuccessEvent{ Result: "success" })    

This obviously panics as e was of type ActionSuccessEvent.

Then we can of course cast to the initial type and back to intermediate:

// Works but would that would need to change whenever new types "extending" 
// ActionResultEvent are added
func(e Event) {
  var resultEvent ActionResultEvent

  switch e.(type) {
  case ActionSuccessEvent:
    resultEvent = ActionResultEvent(e.(ActionSuccessEvent))

  case ActionFailureEvent:
    resultEvent = ActionResultEvent(e.(ActionFailureEvent))
  }
  fmt.Println(resultEvent.Result)
} (ActionSuccessEvent{ Result: "success" })

Another really nice approach from my point would be:

// Error: use of e.(type) outside type switch
func(e Event) {
  resultEvent := ActionResultEvent(e.(type))
} (ActionSuccessEvent{ Result: "success" })

Can anybody think of a smooth solution? One side note: I am happy if the handler panics during runtime whenever a typecast fails, as the wrapper will recover from that.

This is the example code above on the playground. Thanks!

Upvotes: 0

Views: 1122

Answers (1)

tworabbits
tworabbits

Reputation: 1213

Although I got down votes here, I believe this could be of interest to others. So I decided to post the solution to what I have figured out to work: See the playground

If this is bad practice or not "the go way" of doing things I would be really happy to get some feedback. Thanks!

Upvotes: 1

Related Questions