How to pass channel slice to empty interface

Can I pass a slice channel into a function taking chan interface{}? Compiler wouldn’t allow me. Without channel it’s ok.

https://play.golang.org/p/C2UpLSe-CT

package main


func main() {
	slice1 := make([]int,0)
	func1(slice1)
	
	chanSlice1 := make(chan []int)
	func2(chanSlice1)
}

func func1(x interface{}) {}

func func2(x chan interface{}){}

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.

Generics are not a design goal of Go

But that’s the way to go in Go, as far as I can tell.

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.

1 Like

Thanks for the replies.

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)
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.