英文:
Golang: optimal way of typing associative slices?
问题
我正在解析大量的HTTP日志,目标是告诉每个IP地址生成了多少个请求。
我首先做的是:
var hits = make(map[string]uint)
// 这样我就可以填充它
hits[ipAddr]++
然而,我想让它变得“有类型”,这样一来,hits[string]uint
就会立即清楚地使用IP地址作为字符串标识符。我想,也许一个结构体可以帮助我:
type Hit struct {
IP string
Count uint
}
但这样做(我认为)会损失性能,因为现在我必须真正查找特定的Hit来增加它的计数。我容忍自己可能有点多疑,可以简单地使用循环:
var hits = make([]Hit)
// TrackHit 只是简单地跟踪它
func TrackHit(ip string) {
for hit, _ := range hits {
if hit.IP == ip {
hit.Count++
return
}
}
append(hits, Hit{
IP: ip,
Count: 0,
})
}
但这看起来... 不太优化。我认为,任何可以用一行代码写出的东西都会让你作为专业人士闪耀,而当一行代码变成13行时,我倾向于感觉“嗯?我在这里做错了什么吗?”
在Go语言中有没有一行代码的解决方案?
谢谢
英文:
I'm parsing loads of HTTP logs pursing a goal tell how many requests each IP address generated.
The first thing I did is:
var hits = make(map[string]uint)
// so I could populate it with
hits[ipAddr]++
However, I would like to make it "typed", so that it would be immediately clear that hits[string]uint
uses an IP address as a string identifier. I thought, well maybe a struct can help me:
type Hit struct {
IP string
Count uint
}
But that way (I think) I'm loosing the performance, because now I how to really look for specific Hit to increment it's count. I tolerate that I could be paranoid here, and could simple go for the loop:
var hits = make([]Hit)
// TrackHit just damn tracks it
func TrackHit(ip string) {
for hit, _ := range hits {
if hit.IP == ip {
hit.Count++
return
}
}
append(hits, Hit{
IP: ip,
Count: 0,
})
}
But that just looks ... suboptimal. I think everything that could be written in 1 line makes you shine as professional, and when 1 line turns into 13, I tend to feel "whaaa? Doing something wrong here, mom?"
Any typed one-liners here in Go?
Thanks
答案1
得分: 4
如Uvelichitel指出的,你可以使用一个带类型的字符串:
type IP string
var hits = make(map[IP]uint)
hits[IP("127.0.0.1")]++
或者你可以使用现有的stdlib IP类型:
var hits = make(map[net.IP]uint)
hits[net.ParseIP("127.0.0.1")]++
无论哪种方式,都可以清楚地表明你正在引用IP地址,而不需要为每次递增循环遍历结构体切片引入额外的开销。后者的优点是为你提供了完整的stdlib支持,以便进行任何其他IP操作,并且具有更紧凑的表示形式(IPv4地址为4个字节,而不是7-15个字符的UTF-8字符串),但需要解析字符串。哪种方式更好将取决于你的具体用例。
英文:
As Uvelichitel pointed out, you can use a typed string:
type IP string
var hits = make(map[IP]uint)
hits[IP("127.0.0.1")]++
Or you could use the existing stdlib IP type:
var hits = make(map[net.IP]uint)
hits[net.ParseIP("127.0.0.1")]++
Either would make it clear that you're referring to IPs, without the overhead introduced by looping over a slice of structs for every increment. The latter has the advantage of giving you full stdlib support for any other IP manipulation you need to do, and a more compact representation (4 bytes for IPv4 addresses instead of a 7-15 character UTF-8 string), at the cost of parsing the strings. Which one is better will depend on your specific use case.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论