Scenario
You would like to define a Golang function which accepts different types (or structs) and take different actions depending on your input. This is very similar to the “visitor design pattern”
A good example is marshalling the response of an http.Get call differently depending on your input to this function
Method
The obvious trick is to use interface{} as the input type to the function, then use switch interfaceArg.(type) to determine what action to take
What is not so obvious is that assigning the result of interfaceArg.(type) allows you to modify your input arg in place. This assignment would look like so:
switch v := (interfaceArg).(type)
...
Without this assignment (to v in our example above/below), the compiler would complain that you are attempting to assign mismatched types. With the assignment, the compiler can infer what type the input variable is and so compiles successfully
Example
func GetIfconfigApi(responseStruct interface{}) error {
resp, err := http.Get("http://ifconfig.io/all.json")
if err != nil {
fmt.Println("[ERROR] GetIfconfigApi: ", err)
return err
}
body := resp.Body
defer resp.Body.Close()
bodyContent, err := io.ReadAll(body)
if err != nil {
fmt.Println("[ERROR] GetIfconfigApi: ", err)
return err
}
switch v := (responseStruct).(type) { //this assignment is important
case *string:
fmt.Println("hit string")
*v = string(bodyContent)
case *[]byte:
*v = bodyContent
default:
json.Unmarshal(bodyContent, responseStruct)
}
return nil
}
// Examples of calling the above
type TestStruct struct {
CountryCode string `json:"country_code"`
Forwarded string
}
var testStruct TestStruct
var testString string
var testBytes []byte
Tutela.GetIfconfigApi(&testStruct)
fmt.Println(testStruct)
fmt.Println("------")
Tutela.GetIfconfigApi(&testString)
fmt.Println(testString)
fmt.Println("------")
Tutela.GetIfconfigApi(&testBytes)
fmt.Println(testBytes)
fmt.Println("------")