This takes up unnecessary space—use map[T]struct{} instead, which also explains to anyone reading the code that the value isn't used.
This takes up unnecessary space—use map[T]struct{} instead, which also explains to anyone reading the code that the value isn't used.
if myset[thing] { ... }
With a map[T]struct(), you end up with:
if _, ok := myset[thing]; ok { ... }
Sometimes, the saving in space is TOTALLY worth the extra verbosity. Sometimes, the slight clarity from "non-existent keys return the zero value" wins.
Using a "set's" value in an if statement doesn't make sense either, compared to
if _, exists := something[item]; exists { ... }
which is explicit regarding what's actually going on.As Rob said, "Clear is better than clever." https://www.youtube.com/watch?v=PAAkCSZUG1c&t=875s
I also don't want to be hunting down whoever creates a map[T]bool and doesn't leave a comment explaining it's a set ;)
Hopefully we won't have to worry about it for much longer regardless, since I imagine we'll be using proper sets (with methods) some point in the near future.
But, that's one of those "requires extensive documentation" (and ideally, wrapping in a custom type and provide methods for checking and manipulating the set(s)).
In either way, even with that type of data type underlying a set, I would (probably) provide a functional API to interact with it.
m["x"] = foo()
for k := range {
// if foo returned false, this is buggy
}for k, v := range m { if v { } }
But it also allows you to use "if m[key] { ... }". It is literally a trade-off for what convenience you want. And in both cases, you should (probably) wrap an abstraction around the raw map.