Implementing Sets in Golang: A Practical Guide
Grace Collins
Solutions Engineer · Leapcell

Key Takeaways
- Go lacks a built-in
Set
type, but maps provide an efficient alternative. - Using
struct{}
as the map value optimizes memory usage. - Third-party libraries like
golang-set
offer advanced set operations.
In Go, there isn't a built-in Set
data structure as found in some other programming languages. However, Go's map type provides a convenient way to implement a set, leveraging the uniqueness of map keys to ensure that each element in the set is distinct.
Implementing a Set Using a Map
A common approach to creating a set in Go is to use a map with keys representing the set elements and empty struct values. The empty struct (struct{}
) is preferred because it occupies zero bytes of storage, making it an efficient choice. Here's an example of how you might define and use such a set:
package main import "fmt" // Set represents a collection of unique elements. type Set struct { m map[interface{}]struct{} } // NewSet initializes a new set with the given elements. func NewSet(items ...interface{}) *Set { s := &Set{ m: make(map[interface{}]struct{}), } s.Add(items...) return s } // Add inserts elements into the set. func (s *Set) Add(items ...interface{}) { for _, item := range items { s.m[item] = struct{}{} } } // Remove deletes an element from the set. func (s *Set) Remove(item interface{}) { delete(s.m, item) } // Contains checks if an element is in the set. func (s *Set) Contains(item interface{}) bool { _, exists := s.m[item] return exists } // Size returns the number of elements in the set. func (s *Set) Size() int { return len(s.m) } // Clear removes all elements from the set. func (s *Set) Clear() { s.m = make(map[interface{}]struct{}) } // Elements returns a slice of all elements in the set. func (s *Set) Elements() []interface{} { elements := make([]interface{}, 0, len(s.m)) for key := range s.m { elements = append(elements, key) } return elements } func main() { s := NewSet(1, 2, 3, "four") s.Add(5) s.Remove(2) fmt.Println(s.Contains(3)) // Output: true fmt.Println(s.Size()) // Output: 4 fmt.Println(s.Elements()) // Output: [1 3 four 5] s.Clear() fmt.Println(s.Size()) // Output: 0 }
In this implementation:
NewSet
initializes the set and adds any provided elements.Add
inserts new elements into the set.Remove
deletes an element from the set.Contains
checks for the existence of an element.Size
returns the number of elements.Clear
removes all elements.Elements
retrieves all elements as a slice.
This structure ensures that each element is unique and provides efficient operations for adding, removing, and checking elements.
Using Third-Party Libraries
For more advanced set operations and features, you might consider using third-party libraries such as golang-set
. This library offers a rich set of functionalities, including thread-safe and non-thread-safe implementations, and supports various set operations like unions, intersections, and differences.
To use golang-set
, first install it:
go get github.com/deckarep/golang-set/v2
Here's an example of how to use it:
package main import ( "fmt" mapset "github.com/deckarep/golang-set/v2" ) func main() { s := mapset.NewSet[int]() s.Add(1, 2, 3) s.Remove(2) fmt.Println(s.Contains(3)) // Output: true fmt.Println(s.Cardinality()) // Output: 2 fmt.Println(s.ToSlice()) // Output: [1 3] }
In this example, golang-set
provides a generic set implementation with methods like Add
, Remove
, Contains
, Cardinality
(to get the number of elements), and ToSlice
(to retrieve all elements as a slice).
Performance Considerations
When implementing a set using a map, the choice of the map's value type can impact performance. Using an empty struct (struct{}
) as the value type is often recommended because it doesn't consume additional memory. Benchmark tests have shown that maps with struct{}
values can be more memory-efficient compared to other types like bool
or int
.
In summary, while Go doesn't have a built-in set type, its map type allows for efficient and flexible implementations of set functionality, either through custom implementations or by utilizing third-party libraries.
FAQs
Go’s philosophy favors simplicity, and its map type effectively supports set operations.
struct{}
consumes zero bytes, making it more memory-efficient.
If you need advanced features like union, intersection, or thread safety, a library is beneficial.
We are Leapcell, your top choice for hosting Go projects.
Leapcell is the Next-Gen Serverless Platform for Web Hosting, Async Tasks, and Redis:
Multi-Language Support
- Develop with Node.js, Python, Go, or Rust.
Deploy unlimited projects for free
- pay only for usage — no requests, no charges.
Unbeatable Cost Efficiency
- Pay-as-you-go with no idle charges.
- Example: $25 supports 6.94M requests at a 60ms average response time.
Streamlined Developer Experience
- Intuitive UI for effortless setup.
- Fully automated CI/CD pipelines and GitOps integration.
- Real-time metrics and logging for actionable insights.
Effortless Scalability and High Performance
- Auto-scaling to handle high concurrency with ease.
- Zero operational overhead — just focus on building.
Explore more in the Documentation!
Follow us on X: @LeapcellHQ