转:类型切换声明中的这种多重情况条件有什么问题?
我的代码一般是这样的:转:类型切换声明中的这种多重情况条件有什么问题?
func BulkInsert(docs interface{}) {
switch data := docs.(type) {
case map[string] *model.SnapshotByConv, map[string] *model.UserSnapshotsMap:
for ver, _ := range data {
// other logics ...
}
case map[int64] map[string] *model.Delta:
for ver, _ := range data {
// other logics ...
}
}
}
然后当编译我得到了错误: cannot range over data (type interface {})
,它是由第一range
提高。
如果我删除了多种在第一种情况下,这意味着把它作为case map[string] *model.SnapshotByConv:
然后编译错误消失了,这是wried,我需要继续在这两种类型完全相同的逻辑,所以为什么我不能把它们放在同一个case
?
请帮助,谢谢。
我认为这里的情况与已经在这里得到的答案不一样:golang multiple case in type switch,它试图找到一种方法来识别类型,但这里是我只是不想识别某些类型,只是运行它的一些逻辑,我找不到一个优雅的方式来做到这一点。
如果案例列举多种类型(如您的例子),变量的类型将不会缩小,因此您的案例将是interface{}
。这就是你链接到的问题所说的,并且没有办法绕过它。
要为两种不同类型的情况派发一些通用代码,您需要在中间介绍一个接口。 (如果Go在某些时候引入泛型,但从外观来看,这种情况可能会发生变化,即使这种情况发生也不会很快发生。)有几种方法可以做到这一点,这里有三种:
1 - Define类型为您的地图,并添加一个通用接口
不要直接使用地图,而要定义类型为地图,并为其添加功能。
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 - 使地图保持通用的接口
不要创建指针的地图,但你的快照类型的共享接口映射。
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 - 打出来的逻辑,并使其回叫到公共接口
拆分开关壳体分成两个独立的情况下,但打出来的逻辑转换成可以在任快照类型操作的功能。这样,你不必重复逻辑。
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)
}
// ...
}
请注意,在所有这三种情况下,都有一个接口将公共逻辑与逻辑所作用的对象分开。必须必然引入逻辑和对象之间的动态绑定,以通过接口或例如完成您所描述的内容。创建一个捕获对象的匿名函数传递给逻辑。
比你非常为这个如此详细的答案和真棒解释。事实证明,最后我需要'json.Marshal'数据,所以即使对于这两种类型,我仍然需要清楚地知道类型,底层结构定义。再次感谢你。 – lnshi
你不需要有一个类型化的变量将其编组为json。如果你看看'json.Marshal'的签名(https://golang.org/pkg/encoding/json/#Marshal),你会发现它需要'interface {}'。 'json'包使用反射来找出结构定义。 –
可能重复[golang multiple case in type switch](http://*.com/questions/40575033/golang-multiple-case-in-type-switch) –
@timCooper是的,那么我知道它不会像上面这样工作,但我的情况下优雅的解决方案是什么?我不需要确定这两种类型,只需要对数据进行排序。试图把代码放在'default'中,仍然编译错误。 – lnshi
如果你想让相同的代码对不同的类型进行操作,那通常意味着你应该定义一个接口来封装所需的功能,然后为这些类型实现该接口。 –