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.

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