If the case enumerates multiple types (like it does in your example), the variable's type won't be narrowed, so in your case it will be interface{}
. This is what the question you link to says, and there is no way around it.
To dispatch some generic code for two different type cases, you will need to introduce an interface somewhere inbetween. (This might change if Go at some point introduces generics, but from the looks of it, that won't happen soon if ever.) There are a few ways you could do this, here are three:
1 - Define types for your maps, and add a common interface
Don't use the maps directly, but define types that are maps, and add functions to them.
type SnapshotMap map[string]*model.SnapshotByConv
type UserSnapshotMap map[string]*model.UserSnapshotsMap
func (sm *SnapshotMap) DoLogic() {/*...*/}
func (usm *UserSnapshotMap) DoLogic() {/*...*/}
type LogicDoer interface {
DoLogic()
}
// ...
switch data := docs.(type) {
case LogicDoer:
data.DoLogic()
// ...
}
2 - Make the maps hold a common interface
Don't create maps of pointers, but maps of interfaces that your snapshot types share.
type Snapshot interface {
LogicCommonToSnapshots()
}
var doc interface{}
// Somewhere else, this happens rather than a creating map[string]*Something
doc = make(map[string]Snapshot)
// ...
switch data := doc.(type) {
case map[string]Snapshot:
for ver, _ := range data {
ver.LogicCommonToSnapshots()
}
// ...
}
3 - Break out the logic and make it call back onto a common interface
Split the switch case into two separate cases, but break out the logic into a function that can operate on either snapshot type. That way, you won't have to duplicate the logic.
type Snapshot interface {
LogicCommonToSnapshots()
}
func ComplexLogic(s Snapshot) {/*...*/}
switch data := doc.(type) {
case map[string] *model.SnapshotByConv:
for ver, _ := range data
ComplexLogic(ver)
}
case map[string] *model.UserSnapshotsMap:
for ver, _ := range data {
ComplexLogic(ver)
}
// ...
}
Notice that in all three cases, there is an interface that separates the common logic from the object that logic acts on. You must necessarily introduce a dynamic binding between the logic and the object to accomplish what you describe, either through interfaces or by e.g. creating an anonymous function that captures the object gets passed to the logic.