英文:
go: filter events in select and break
问题
这是我目前的代码:
for {
select {
case event := <-events:
if event.Msg != nil && len(activeFilters) > 0 {
// 过滤消息
matches := false
for k, v := range activeFilters {
if k == event.Msg.Namepace {
for _, code := range v {
if code != event.Msg.Code {
matches = true
break //BREAK1
}
}
if matches {
break //BREAK2
}
}
}
if !matches {
break //BREAK3
}
}
if err := sendEvent(event); err != nil {
sendErr(err)
return
}
case <-closed:
return
}
}
首先,我是Go的初学者。对我来说,上面的代码看起来过于复杂,我猜它可以进行优化。
我想要做的是:当一个事件到达时,我想要检查给定的Code是否在过滤器列表中。过滤器有两个"维度":一个是命名空间,一个是代码列表。activeFilters
是一个map[string][]uint64
。(注意:我可以重新设计activeFilters
为其他结构)。
所以,我只想在过滤器匹配时阻止代码执行sendEvent
,而当协议与activeFilters
中的任何键匹配且消息代码包含在该键的值数组中时,应该执行sendEvent
。
那么上面的代码可以简化吗?break
的使用(BREAK1和BREAK2)是否正确?对我来说,BREAK2似乎是必需的,因为内部的for
循环可能已经找到了一个匹配项,这种情况下就没有必要继续迭代activeFilters
。
最后,我在使用BREAK3时是否正确?我在那里的想法是,如果没有匹配项,我不想执行sendEvent
,所以我想跳出case
。在我有限的Go理解中,使用return
会关闭通道或类似的操作...
英文:
This is the code I have so far:
for {
select {
case event := <-events:
if event.Msg != nil && len(activeFilters) > 0 {
//filter for messages
matches := false
for k, v := range activeFilters {
if k == event.Msg.Namepace {
for _, code := range v {
if code != event.Msg.Code {
matches = true
break //BREAK1
}
}
if matches {
break //BREAK2
}
}
}
if !matches {
break //BREAK3
}
}
if err := sendEvent(event); err != nil {
sendErr(err)
return
}
case <-closed:
return
}
}
First, I am a beginner in Go. The above code generally looks too complex for me, I guess it can be optimized.
What I want to do: when an event arrives, I want to check if a given Code is inside a list of filters. The filters have two "dimensions": a namespace and a list of codes. activeFilters
is a map[string][]uint64
.
(Note: I am allowed to redesign activeFilters
to some other structure).
So I just want to prevent the code to execute sendEvent
if the filter doesn't match, while sendEvent
should be executed if the protocol matches any key in activeFilters
AND the message code is contained in the value array for that key.
So can the above code be simplified? Is the usage of break
(BREAK1 and BREAK2) correct? BREAK2 seems to be needed for me because the inner for
loop may already find a match, in which case there's no need to continue iterating on activeFilters
.
And finally, am I correct in using BREAK3? My thinking there is that if there is no match, I do not want to execute sendEvent
, so I want to jump out of the case
. In my limited Go
understanding, using return
there would close the channel or something like that....
:blush
答案1
得分: 1
如果activeFilters
是一个map
,你不需要迭代它来查找一个键 - 这就是map
的全部意义。你可以这样做:
if v, ok := activeFilters[event.Msg.Namepace]; ok {
// 遍历 v,就像你现在做的那样
} else {
// event.Msg.Namepace 在 map 中不存在
}
这样就消除了一个循环,因此也消除了一个break
。最后一个break
(BREAK 3)是有效的,但不太清楚它在做什么;我会将其改为条件语句,以使其更易读:
if matches {
if err := sendEvent(event); err != nil {
sendErr(err)
return
}
}
return
不会关闭通道(假设在其他地方还有对它的引用,否则这个代码根本无法工作),但它会退出循环,因此不会处理更多的消息。我还会再次检查错误情况下的返回值是否真的是你想要的;通常在这种情况下,你会记录错误,但继续处理未来通过通道传递的消息。
英文:
If activeFilters
is a map
, you don't need to iterate it to find a key - that's the whole point of a map
. You can just:
if v,ok := activeFilters[event.Msg.Namepace]; ok {
// range over v as you are now
} else {
// event.Msg.Namepace does not exist in the map
}
This eliminates one loop, and thus one break
. The last break
(BREAK 3) works but isn't particularly clear what it's doing; I'd make it a conditional to make it more readable:
if matches {
if err := sendEvent(event); err != nil {
sendErr(err)
return
}
}
return
would not close the channel (assuming there's another reference to it somewhere else, which there would have to be for this to work at all), but it would exit your loop, so no further messages would be processed. I'd also double-check that the return in the error case is really what you want; typically in these situations you'd log the error but keep handling future messages that come over the channel.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论