-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
What did you do?
package main
import (
"fmt"
)
type A struct {
s string
}
func (a A) String() string {
return "I am " + a.s + "\n"
}
func main() {
a := []A{{"a"}, {"b"}}
b := map[string]A{"a":{"a"}, "b":{"b"}}
var i1, i2 interface{}
i1 = a
i2 = b
switch v := i1.(type) {
case []fmt.Stringer:
for _,s := range v {
fmt.Print(s.String())
}
default:
fmt.Println("Failed")
}
switch v2 := i2.(type) {
case map[string]fmt.Stringer:
for _,s := range v2 {
fmt.Print(s.String())
}
default:
fmt.Println("Failed")
}
}
What did you expect to see?
I am a
I am b
I am a
I am b
What did you see instead?
Failed
Failed
Discussion
I realize this is currently as designed. I also realize there are other related issues around this, including generics, but I think this might be an inexpensive way of achieving a variety of goals.
Since this is within a type switch, there is an understanding with the developer that there is potential performance impacting type juggling going on. By controlling the order of the switch statements, the developer can decide when to ask the compiler to consider a slice or map of objects as to whether the inner object matches an interface.
I also realize that there is a type conversion issue inside of the for statements. A possible solution is that a type assertion in this way might cause the slice or map variable to have an internal indicator that if it is ranged over inside of the case, it will return the asked for interface instead. There are recursion issues here too, but that should be no problem since the asked for interface is inside of the returned type assertion variable, and a recursive type switch would create a new variable. So yes, its complex, but should be doable and quite helpful.