4

I have two golang functions, doing exactly same thing, one takes input a slice and the other takes a map as input. I want to combine this into one function, to avoid duplication.

func DoSomething([]data) {
//do something.
}

func DoSomething(map[string]data) {
    //do something.
}

Combined function may look like:

    func DoSomethingNew (param type) {
       //param could be map or slice
    }

I want to know if it is possible to pass different types to same function in golang and how. I googled but couldn't find anything relevant.

Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
SeattleOrBayArea
  • 2,808
  • 6
  • 26
  • 38

2 Answers2

7

You can use interfaces Go Playground

func F(data interface{}) {
    switch data.(type){
    case []int:
        fmt.Println("Slice")
        fmt.Println(data)
    case map[string]int:
        fmt.Println("Map")
        fmt.Println(data)
    }

    fmt.Println()
}

where you actually check for the type and do something based on the type.

Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
  • thanks for your answer, I have a follow up question, although I got answer to my original question. Interface solves the problem. But I wanted to not detect types (if possible, also I expect only either map or slice types) and then have a for loop using range over data. That doesnt seem to work: https://play.golang.org/p/jggFscxfHx . Because I cannot range over interface. – SeattleOrBayArea Nov 26 '15 at 00:15
  • 1
    @GauravSinha take a look at this Q/A http://stackoverflow.com/questions/14025833/range-over-interface-which-stores-a-slice It sounds exactly like the thing you want. – Salvador Dali Nov 26 '15 at 00:17
  • 1
    nice, didn't know much about reflection. Thanks :) :thumbsup – SeattleOrBayArea Nov 26 '15 at 00:29
  • Looking at my code now, I think I am still repeating my code in the new function. Only difference being it is now in the form of a switch case, rather than two functions. But good to learn about interfaces and reflection though. – SeattleOrBayArea Nov 26 '15 at 00:44
3

There are several ways you could do this, but the simple way would be to make it so DoSomethingNew accepts the interface{} type. Inside of the method you would then do a type switch or in this case with only two options, perhaps just one type assertion, followed by the other, returning error if both fail. Another option would be to have both as arguments and check for nil inside the function with a similar if, else-if, else pattern to handle the error if the input is of neither types you're looking for. To make your code more safe you could move to a more strict interface than the empty one which all types implement. You could also do some method chaining or even implement the method with using the types themselves as the receiving type. Here's an example that shows a few of the ideas; https://play.golang.org/p/_v2AyFjGzv

evanmcdonnal
  • 46,131
  • 16
  • 104
  • 115