Passing slices of structs as empty interfaces to a function

I have many data structures such as :

type dbClusters struct {
  some struct members
}

type dbHostStates struct {
  some struct members
}

And another struct defined as such:

type tableInfo struct {
  tablename string
  datastructure []interface{}
}

Somewhere in my code, I use those structs this way:

func myFunc() {
  var clusters []dbClusters
  var states []dbHostStates

  [some code to populate the structs]

  tables := tableInfo {
    tableInfo { tablename: "clusterstable", datastructure: clusters },
    tableInfo { tablename: "statestable", datastructure: states }
  }
}

The goal here is later in my code, I’ll have a single function that will be called with []tableInfo as param to process whatever data in the table tableInfo.tablename, using the data structure in tableInfo.datastructure.

I thought that having that info in a struct tableInfo was the proper way, and using an empty interface to map with the actual data structure was “clever”.

The reason I want to go this way is that I might have as 15 tables to handle, I do not wish to duplicate the near-same code 15 times.

What I am missing or misunderstanding here ?

Trying to build, I get this:

[21:43:58|jfgratton@bergen:source]: ./build.sh 
# vmman3/db
db/db-import.go:47:54: cannot use hyps (variable of type []dbHypervisors) as type []interface{} in struct literal
db/db-import.go:48:55: cannot use sps (variable of type []dbStoragePools) as type []interface{} in struct literal
db/db-import.go:49:50: cannot use vms (variable of type []dbVmStates) as type []interface{} in struct literal

I understand what it says, not why it says so.

Hi!

Golang does not allow direct conversion/assignment of slices of certain type to []interface{} as explained here: Frequently Asked Questions (FAQ) - The Go Programming Language .

You will need to convert to []interface{} first before assigning it to datastructure.

func myFunc() {
  var clusters []dbClusters
  var states []dbHostStates

  [some code to populate the structs]

  dbC := make([]interface{}, len(clusters))
  for i, v := range clusters {
    dbC[i] = v
  }

  dbS := make([]interface{}, len(states))
  for i, v := range states {
    dbS[i] = v
  }

  tables := tableInfo {
    tableInfo { tablename: "clusterstable", datastructure: dbC },
    tableInfo { tablename: "statestable", datastructure: dbS }
  }
}

I’ve found a similar answer as you replied. It kind of defeats the purpose of what I was going to try. Inasmuch as I love Go, so far (me, the Go newbie), I guess I still have to unlearn some OOP concepts and learn the GO way.
From the FAQ you’ve provided (how did I miss that ??), I understand the reason underlying this.

This means then that I’ll some code near-duplication for every table I have to go through, then. I wanted to build some kind of TableInjectorFactory() function, but …

Thanks for the reply @ditchx !

You could also explore if generics would work for you:

https://gobyexample.com/generics

Simplest way to use generics to remove duplication your code is to use a generic function which converts your slices to []interface{}. The code will now look something like:

// Generic function to convert slices of any type to []interface{}
func dataStructure[T any](s []T) []interface{} {
	ds := make([]interface{}, len(s))
	for i, v := range s {
		ds[i] = v
	}

	return ds
}

func myFunc() {
  var clusters []dbClusters
  var states []dbHostStates

  [some code to populate the structs]

  dbC := dataStructure[dbClusters](clusters)
  dbS := dataStructure[dbHostStates](states)

  tables := tableInfo {
    tableInfo { tablename: "clusterstable", datastructure: dbC },
    tableInfo { tablename: "statestable", datastructure: dbS }
  }
}

My understanding of generics is that it is a way to circumvent the lack of function overloading in GO, am I right ?

I intend to look that one up in the next iteration of my software. This project is my “learning” project (a Python3 to GO port of a QEMU vm manager).

This is exciting so far; so many possibilities with GO…

Bookmarked your link, will definitely look it up soon. I want to get this iteration of my software out of the door ASAP, then refine it.