Golang:关联切片的最佳键入方式是什么?

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

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.

huangapple
  • 本文由 发表于 2017年5月19日 20:01:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/44069593.html
匿名

发表评论

匿名网友

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

确定