过滤选择和中断中的事件

huangapple go评论89阅读模式
英文:

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 := &lt;-events:
		if event.Msg != nil &amp;&amp; len(activeFilters) &gt; 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 &lt;-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.

huangapple
  • 本文由 发表于 2017年7月12日 05:04:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/45044434.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定