Hacker News new | ask | show | jobs
by jrockway 1764 days ago
map[T]struct{} is the set type in Go. (Note that struct{} is represented with 0 bytes of memory, so it's not chaff.)

You might like the slices proposal for utility functions like these: https://github.com/golang/go/issues/45955

1 comments

Thanks. I wasn't aware that struct{} is zero-sized, so that plugs that hole.

I'll admit freely that I'm not a proficient Go programmer, so it's easier for me to see the things I don't like than the things that Gophers praise. But even this solution leaves me unsatisfied, in contrast to what I'd reach for in Rust or even C++: it requires that I know that struct{} is zero-sized, and I still have to do the manual legwork of writing a CS101 dedupe function.

Zero Size optimisations are a thing in Rust too though, and I don't think an empty struct being zero size is any more surprising than Rust's empty tuple being zero size.

Like, if you tell Rust you want 4 million empty tuples in a vector, it will give you a vector with exactly 4 million empty tuples in it and no heap allocation because those empty tuples don't take space, so, 4 million of them also doesn't take up any space.

The key difference being knowledge: I don't have to know `HashSet` is really just a map with a ZST to use it efficiently. All I need to know is that I don't need a value, and the ecosystem obliges me. This in contrast to Go, where I need to know that `struct{}` is a ZST, that the "right" way to do a set is to use it as the map value, &c.
There is also a WIP Go proposal for adding a set to the standard library using the upcoming generics:

https://github.com/golang/go/discussions/47331

Fun thing, is Rust employs the same trick. The HashSet<T> is an alias for HashMap<T, ()>. "()" is the unit type. Which is zero-sized.

Because Rust has generics, it is more ergonomic though.

https://doc.rust-lang.org/std/collections/struct.HashSet.htm...