I will have an application with many messages adhering to a Req/Rsp design. Implemented below is a single Req/Rsp for the message Foo. A Req will adhere to a common interface for processing the message and return a response. All Rsp messages will embed the MHRSP struct. I'd like to set the response status outside of the ProcessRequest method. The issue I am having, is a runtime fault resulting from the block of code below marked Problem Area
panic: interface conversion: interface {} is *main.FooRsp, not main.MHRSP
Since I will have many messages, not just FooRsp, casting to FooRsp is not the solution, so the question is, how do I handle this in a generic way (i.e. able to set Success and Error Message for any Rsp)?
Code compiled using GDB Online: https://www.onlinegdb.com/online_go_compiler
/******************************************************************************
Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, Java, PHP, Ruby, Perl,
C#, VB, Swift, Pascal, Fortran, Haskell, Objective-C, Assembly, HTML, CSS, JS, SQLite, Prolog.
Code, Compile, Run and Debug online from anywhere in world.
*******************************************************************************/
package main
import (
"fmt"
"errors"
"encoding/json"
)
type MHREQIF interface {
ProcessRequest(e int) (interface{}, error)
}
type MHRSP struct {
Success bool `json:"success,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
}
type FooReq struct {
MHREQIF
Name string `json:"name"`
}
type FooRsp struct {
MHRSP
Name string `json:"name"`
}
func (self *FooReq) ProcessRequest(e int) (interface{}, error) {
rsp := FooRsp{Name:self.Name}
if 0 == e {
return &rsp, nil
} else {
return &rsp, errors.New("crap")
}
}
func main() {
var msg_req MHREQIF
msg_req = &FooReq{Name:"bob"}
rsp, err := msg_req.ProcessRequest(1)
if err != nil {
// -------------- PROBLEM AREA BEG ------------------
v := rsp.(MHRSP)
v.Success = false
v.ErrorMessage = fmt.Sprintf("%v", err)
// -------------- PROBLEM AREA END ------------------
}
msg_bytes, _ := json.Marshal(rsp)
msg_string := string(msg_bytes)
fmt.Println(msg_string)
}
Thanks to @mkopriva and @Adrian for pointing me in the right direction. Sometimes that shift from C++ OO to go-isms is mind bending :P
Here is the working code for anyone with a similar struggle on how to tackle this kind of issue.
/******************************************************************************
Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, Java, PHP, Ruby, Perl,
C#, VB, Swift, Pascal, Fortran, Haskell, Objective-C, Assembly, HTML, CSS, JS, SQLite, Prolog.
Code, Compile, Run and Debug online from anywhere in world.
https://www.onlinegdb.com/online_c++_compiler
*******************************************************************************/
package main
import (
"fmt"
"errors"
"encoding/json"
)
type MHREQIF interface {
ProcessRequest(e int) (MHRESPIF, error)
}
type MHRESPIF interface {
SetResponse(err error)
}
type MHRSP struct {
MHRESPIF `json:"-"`
Success bool `json:"success"`
ErrorMessage string `json:"error_message,omitempty"`
}
type FooReq struct {
MHREQIF
Name string `json:"name"`
}
type FooRsp struct {
MHRSP
Name string `json:"name"`
}
func (self *MHRSP) SetResponse(err error) {
if err != nil {
self.Success = false
self.ErrorMessage = fmt.Sprintf("%v", err)
} else {
self.Success = true
}
}
func (self *FooReq) ProcessRequest(e int) (MHRESPIF, error) {
rsp := FooRsp{Name:self.Name}
if 0 == e {
return &rsp, nil
} else {
return &rsp, errors.New("crap")
}
}
func main() {
var msg_req MHREQIF
msg_req = &FooReq{Name:"bob"}
rsp, err := msg_req.ProcessRequest(1)
rsp.SetResponse(err)
msg_bytes, _ := json.Marshal(rsp)
msg_string := string(msg_bytes)
fmt.Println(msg_string)
}