-1

I am having trouble understanding why type switches are written with an additional variable defined in the switch statement. The below code seems to be the sanctioned way of doing things:

func test_func(i interface{}) {
    switch v := i.(type) {
    case int:
        fmt.Printf("%T\n", v)
    case float64:
        fmt.Printf("%T\n", v)
    case int:
        fmt.Printf("I don't know about type %T!\n", v)
    }
}

func main() {
    test_func(float64(34))
    test_func(int(34))
    test_func("hello world")
}

As expected, this returns:

float64
int
I don't know about type string!

However, I can change test_func slightly so that v is not defined in the switch statement, and instead we use i inside our case statements:

func test_func(i interface{}) {
    switch i.(type) {
    case int:
        fmt.Printf("%T\n", i)
    case float64:
        fmt.Printf("%T\n", i)
    case int:
        fmt.Printf("I don't know about type %T!\n", i)
    }
}

func main() {
    test_func(float64(34))
    test_func(int(34))
    test_func("hello world")
}

And the output is not changed. It seems the two forms are interchangeable. Why would I go to the trouble of defining v when I could just use i? The latter case is simpler since there is one less variable to keep track of; maybe it is even more performant.

  • See https://stackoverflow.com/questions/36091801/avoid-using-type-assertions-in-the-branches-of-a-type-switch and https://golang.org/doc/effective_go.html#type_switch, and https://tour.golang.org/methods/16 – JimB May 10 '19 at 18:07
  • 2
    to add on JimB answer, i is interface{} type, v is typed according to the inner type of i. So if v were a struct with methods defined on it, you could call those methods on v, not i. the code you present to test that is confusing because you are mixing type semantic with print verbs (%T). to finish, no the two forms are NOT interchangeable. –  May 10 '19 at 18:10
  • 2
    Try using `i` in this (https://play.golang.com/p/soqsNXsm_k0) program and see if it compiles. – mkopriva May 10 '19 at 18:14

1 Answers1

0

They are not interchangeable; you're just passing i to a function that can take it regardless of its type (fmt.Printf's arguments after the format string are of type interface{}). i is still its original type, because the type of a variable cannot change.

If you actually wanted to do something with it based on its type, you would need the first form, so that v would be of the type in the case statement. Whether or not you assign the typed value to a variable, the original variable i retains its original type.

This is covered well in the Tour of Go: Type switches

Adrian
  • 42,911
  • 6
  • 107
  • 99
  • Ah, I see. I was confused by the fact that a `%T` in `fmt.Printf` doesn't print `interface{}`, but rather the type that the interface encapsulates. Seems like a strange decision on the part of the developers. Thanks for your help! – Adam Pickering May 10 '19 at 19:53
  • 2
    If it didn't, it would *always* print `interface{}` no matter what you passed in, because that's the type it receives all arguments as. – Adrian May 10 '19 at 20:37