views:

109

answers:

3

The problem I've just faced is what to do in the following case:

func printItems(header string, items []interface{}, fmtString string) {
  // ...
}

func main() {
  var iarr = []int{1, 2, 3}
  var farr = []float{1.0, 2.0, 3.0}
  printItems("Integer array:", iarr, "")
  printItems("Float array:", farr, "")
}

Go has no generics and doesn't allow to use collection covariance:

prog.go:26: cannot use iarr (type []int) as type []interface { } in function argument
prog.go:27: cannot use farr (type []float) as type []interface { } in function argument

Ideas?

A: 
package main

func printItems(header string, items interface{}, fmtString string) {
  // ...
}

func main() {
  var iarr = []int{1, 2, 3}
  var farr = []float{1.0, 2.0, 3.0}
  printItems("Integer array:", iarr, "")
  printItems("Float array:", farr, "")
}

Take a look at similar functions, like fmt.Printf(), in the core Go package documentation and source code.

peterSO
Thanks for reference. Yet, this is not about the essence of the question. Technically, I can replace iarr of ints with iarr of interface{} and my printItems() function will work just fine. It's positively not the nicety I'm interested in. I also took a look into fmt package and "saw and beheld" a lot of reflection underneath. When you need to sew on a button you don't usually use a hammer. Reflection is an abnormal approach, so admit your point at a stretch.
PGene
+2  A: 

There's not really a way to do this right now without either

  1. Making your []int and []float both into []interface{}.
  2. Making printItems accept interface{} instead of []interface{} and then use reflection, similar to what the fmt package does.

Neither solution is pretty.

Evan Shaw
In light of having no generics it looks really strange to me.
PGene
+4  A: 

An example of using reflection:

package main

import (
    "fmt"
    "reflect"
    "strings"
    "container/vector"
)

func printItems(header string, items interface{}, fmtString string) {
    value, ok := reflect.NewValue(items).(reflect.ArrayOrSliceValue)
    if !ok {
        panic("Not an array or slice")
    }

    stringBuilder := new(vector.StringVector)
    stringBuilder.Push(header)

    n := value.Len()
    for i := 0; i < n; i++ {
        stringBuilder.Push(fmt.Sprintf(fmtString, value.Elem(i).Interface()))
    }

    fmt.Println(strings.Join(*stringBuilder, ""))
}

func main() {
    var iarr = []int{1, 2, 3}
    var farr = []float{1.0, 2.0, 3.0}

    printItems("Integer array:", iarr, " %d,")
    printItems("Float array:", farr, " %.1f,")
}
MizardX