How to use sets in Go
Introduction
Go, as a language, does not include a built-in Set data structure like Python or Java. This is one of the features developers miss when transitioning from other languages to Go. However, you can effectively implement sets using Go's map type.
In this post, I'll show you how to use maps as sets, and I'll discuss their advantages and limitations. Whether you're a beginner or an experienced Go developer, this guide will help you understand how to work with sets in Go.
What is a Set?
A set is a collection of unique elements with no specific order that automatically handles duplicate values. Sets are ideal when you need to quickly check if an element is present in a collection or when you want to ensure that each entry is unique.
Common operations on sets include adding elements, removing elements, checking for membership, and performing set operations like union, intersection, and difference.
Why doesn't Go have a built-in Set type?
Go emphasizes simplicity and minimalism in its standard library. Instead of providing specialized data structures like sets, Go encourages developers to use its versatile map type to achieve similar functionality.
Using Maps as Sets
The most idiomatic way to implement a set in Go is by using a map where the keys represent the elements of the set.
The values are typically ignored or set to struct{}
(an empty struct) to save memory.
Here's a simple example of how to create a set using a map:
package main
func main() {
// Initialize a set using a map[string]struct{}
set := make(map[string]struct{})
// Add elements to the set
set["blog.marcnuri.com"] = struct{}{}
set["google.com"] = struct{}{}
set["example.com"] = struct{}{}
// Check if an element is in the set
if _, ok := set["blog.marcnuri.com"]; ok {
println("blog.marcnuri.com is in the set")
}
// Remove an element from the set
delete(set, "google.com")
// Iterate over the set
for key := range set {
println(key)
}
}
In this example:
- We create a set of strings using a map with
struct{}
as the value type. - We add elements to the set using the map keys.
- We check if an element is in the set by using the comma-ok idiom.
- We remove an element from the set using the
delete(set, "element")
function.
Why use struct instead of bool as the value type?
Using struct{}
as the value type is a common practice in Go when you don't need to store any data:
- Using
struct{}
saves memory because it occupies 0 bytes. - Using
bool
introduces ambiguity since the value could befalse
which is confusing when checking for membership.
How to check if a map contains a key, the comma-ok idiom
The comma-ok idiom is a common pattern in Go to check if a map contains a key.
In this example, we use the comma-ok idiom to check if the key "blog.marcnuri.com"
is in the set.
The syntax is as follows:
value, ok := myMap[key]
When you look up a key in a map, you can capture two return values. Here's what happens:
value
is the value stored under that key if it exists (or the zero value if it is missing).ok
is a boolean that indicates whether the key was found.
This idiom is concise and commonly used in Go programs.
In the example, we ignore the value
and only check if the key exists by using the _
(underscore) to discard the value.
Conclusion
While Go doesn't have a native set type, using maps to simulate set behavior is an efficient and idiomatic solution. This approach leverages the simplicity and power of Go’s built-in data structures, allowing you to manage unique elements effortlessly.
By understanding these techniques and patterns, you'll be well-equipped to handle unique collections in your Go projects! Happy coding!