cannot use chanSlice1 (type chan []int) as type chan interface {} in argument to func2
What I eventually want to do is to have a generic function taking various types of empty slice. Inside the function, the flow is pretty much the same but I need to type switch the concrete type out so I can json unmarshall into the right struct. After that I need to pass the channel back into the main function using the same channel and main function will use type conversion to get the slice with value filled. I have multiple slice types corresponding to different structs and I don’t want to write a seperate function for each type to fill their slice from json.unmarshall.
The above flow doesn’t look smooth but that’s all I can think of now. Feel free let me know if I’m totally off the mark.
It all depends on what is the “common flow”. I suspect the solution is custom types that implement the same interface, then pass the interface to the various channels.
But with the extremely generic code posted, nothing can be said.
The following is the “common flow” in question. I have a dozen custom struct type created to map to different response I get from the server. I have commands asking server to give the list of either type1, type 2 or type n. It works but whenever I need to query a new data type from server, I have to cut/paste the following code block and modify the list(SPList) and collection(SPCol) to the new data type. SPCol is a struct with Members field containing the list I need.
I thought it’ll be nicer if I only have one function and can take/return all types of list and I use type switch inside the function to fetch the concrete type. Then if I have one new data type, I can just add one more “case:” under the type switch to match it.
any thoughts on what’s better way to do this?
//currently i'm doing the following function for slices of each custom struct type, start by passing in slice of that struct type
func SPGetURI(x chan SPList) {
c := NewCLIOVClient() // "c" is just a web rest client knowing server address/login credential
var list SPList //currently i have to create an empty slice of this specific type
uri := SPURL
for uri != "" {
data, err := c.GetURI("", "", uri) //launch http.client.Do towards my server
if err != nil {
fmt.Println(err)
os.Exit(1)
}
var page SPCol //server reply may contain multiple pages, each page include some fields along a list of the custom struct type which I need to grab
if err := json.Unmarshal(data, &page); err != nil {
fmt.Println(err)
os.Exit(1)
}
list = append(list, page.Members...) //append list in each page to final list
uri = page.NextPageURI //keep collecting the list for each page until no more pages.
}
x <- list //pass the final list back to main func
}
I ended up using reflection to do what I want. I know it’s slower but for my app, I’d rather to have a generic function instead of having each type create a similar func/method just for its data type.
func main() {
go GetResourceLists("SPTemplate", sptListC)
go GetResourceLists("EG", egListC)
go GetResourceLists("ServerHWType", hwtListC)
}
the above main would use the func below to retrieve HTTP Rest response and unmarshal into different structs. Also, looks like reflect’s Value.Recv and Value.Send can help me with passing slice channel back to the main func.
type getListMap map[string]resource
type resource struct {
listptr interface{}
col interface{}
uri string
logmsg string
}
var listmap = getListMap{
"SPTemplate": resource{
listptr: &[]SPTemplate{},
col: SPTemplateCol{},
uri: SPTemplateURL,
logmsg: "get SPTemplate",
},
"EG": resource{
listptr: &[]EG{},
col: EGCol{},
uri: EGURL,
logmsg: "get EG",
},
"ServerHWType": resource{
listptr: &[]ServerHWType{},
col: ServerHWTypeCol{},
uri: ServerHWTypeURL,
logmsg: "get ServerHW Type",
},
}
func GetResourceLists(x string, i interface{}) {
listptr := listmap[x].listptr
col := listmap[x].col
uri := listmap[x].uri
logmsg := listmap[x].logmsg
log.Debugf(logmsg)
defer timeTrack(time.Now(), logmsg)
lvptr := reflect.ValueOf(listptr)
lv := lvptr.Elem()
colnew := reflect.New(reflect.TypeOf(col))
c := NewCLIOVClient()
for uri != "" {
data, err := c.GetURI("", "", uri)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if err := json.Unmarshal(data, colnew.Interface()); err != nil {
fmt.Println(err)
os.Exit(1)
}
lv.Set(reflect.AppendSlice(lv, colnew.Elem().FieldByName("Members")))
uri = colnew.Elem().FieldByName("NextPageURI").String()
}
iv := reflect.ValueOf(i)
iv.Send(lv)
}