In Go, although there is no traditional collection framework like Java or Python, collection operations can be handled very efficiently through built-in data structures (such as arrays, slices, maps), interfaces, and some standard library tools. With the introduction of generics in Go 1.18, collection operations have become more flexible and scalable.
There are usually several ways to process collections in Go:
- Arrays and slices: Suitable for ordered collections.
- Map: Applicable to key-value pair collections, often used for search, deduplication and other operations.
- Structure and interface: Used to create custom collection types.
Next, we will explain how to use these built-in data structures and generics to efficiently process collections and give code examples.
1. Slice
Slicing is the most commonly used data structure in Go language. It is a dynamic array based on arrays, which can flexibly add and delete elements. You can use slices to simulate most collection operations.
Example: Deduplication
package main import ( "fmt" ) func removeDuplicates(input []int) []int { unique := make([]int, 0, len(input)) seen := make(map[int]struct{}) for _, value := range input { if _, ok := seen[value]; !ok { unique = append(unique, value) seen[value] = struct{}{} } } return unique } func main() { input := []int{1, 2, 3, 3, 4, 5, 5, 6} unique := removeDuplicates(input) ("Unique elements:", unique) }
illustrate:
Use map to record elements that have appeared, and this way removes duplicate elements from the slice.
The time complexity of this operation is O(n), where n is the length of the input slice.
2. Mapping (Map)
Go's map is a hash table implementation suitable for handling collections of key-value pairs. It is often used for search, deduplication, and counting frequency.
Example: Statistical word frequency
package main import ( "fmt" "strings" ) func countWords(text string) map[string]int { wordCount := make(map[string]int) words := (text) for _, word := range words { wordCount[word]++ } return wordCount } func main() { text := "go is awesome go is fast" count := countWords(text) ("Word Count:", count) }
illustrate:
- map[string]int is used to store each word and its occurrence number.
- () is used to split the input text into words.
3. Custom collection type (struct + interface)
The Go language supports creating custom collection types through structures and interfaces. In some cases, using custom structure collections can bring more flexibility.
Example: Custom collection type
package main import ( "fmt" ) type IntSet struct { set map[int]struct{} } // Create a new IntSet collectionfunc NewIntSet() *IntSet { return &IntSet{set: make(map[int]struct{})} } // Add elements to the collectionfunc (s *IntSet) Add(value int) { [value] = struct{}{} } // Determine whether the set contains an elementfunc (s *IntSet) Contains(value int) bool { _, exists := [value] return exists } // Remove elements from the collectionfunc (s *IntSet) Remove(value int) { delete(, value) } // Print collectionfunc (s *IntSet) Print() { for value := range { (value) } } func main() { set := NewIntSet() (1) (2) (3) ("Contains 2:", (2)) // true (2) ("Contains 2:", (2)) // false ("Set contents:") () // 1 3 }
illustrate:
- IntSet is a custom collection type encapsulated by map[int]struct{}, providing methods for collection operations (add, delete, and search).
- Use map to store collection elements and use an empty struct (struct{}) to optimize memory footprint.
4. Use generics to process collections (Go 1.18+)
Go 1.18 introduces generics, greatly enhancing the flexibility and type safety of handling collections. Generics allow you to create collections that can handle multiple data types.
Example: Implementing a general collection using generics
package main import ( "fmt" ) // Generic collectionstype Set[T comparable] struct { items map[T]struct{} } // Create a new collectionfunc NewSet[T comparable]() *Set[T] { return &Set[T]{items: make(map[T]struct{})} } // Add elements to the collectionfunc (s *Set[T]) Add(value T) { [value] = struct{}{} } // Determine whether the set contains an elementfunc (s *Set[T]) Contains(value T) bool { _, exists := [value] return exists } // Print collectionfunc (s *Set[T]) Print() { for value := range { (value) } } func main() { // Integer collection intSet := NewSet[int]() (1) (2) (3) ("Integer Set:") () // String collection strSet := NewSet[string]() ("apple") ("banana") ("cherry") ("String Set:") () }
illustrate:
Generic Set[T comparable] can handle collections of any type.
The T comparable constraint means that the generic type T must be comparable (i.e., it can be compared with the == or != operator).
5. Concurrent collection
Go supports efficient concurrent programming, so you can use Go's concurrency features to create thread-safe collections. In a high concurrency environment, use or to protect the read and write operations of the collection.
Example: Concurrently secure collection
package main import ( "fmt" "sync" ) type ConcurrentSet struct { set map[int]struct{} lock } func NewConcurrentSet() *ConcurrentSet { return &ConcurrentSet{ set: make(map[int]struct{}), } } func (s *ConcurrentSet) Add(value int) { () defer () [value] = struct{}{} } func (s *ConcurrentSet) Contains(value int) bool { () defer () _, exists := [value] return exists } func (s *ConcurrentSet) Remove(value int) { () defer () delete(, value) } func main() { cs := NewConcurrentSet() // Use goroutine to access the collection concurrently var wg for i := 0; i < 10; i++ { (1) go func(i int) { defer () (i) ("Added", i) }(i) } () // View collection content for i := 0; i < 10; i++ { if (i) { ("Contains", i) } } }
illustrate:
Use to allow multiple read operations to be performed simultaneously, while write operations are exclusive, which can improve concurrency performance.
In concurrent scenarios, access to the collection is protected in a mutex lock to ensure thread safety.
Summarize
Slicing and Mapping: is the most commonly used collection type in Go, suitable for ordered data and key-value pair storage, respectively.
Custom collections: Flexible collection types can be created through structures and interfaces to meet more complex needs.
Generic Collections: Generics introduced in Go 1.18 make collection operations more flexible, can handle multiple data types, and avoid type casting.
Concurrent collection: In high concurrency scenarios, the thread safety of the collection can be used or can be ensured.
By combining these technologies, you can handle various collection operations in the Go language very efficiently and flexibly.
This is the end of this article about how to efficiently process collections in Go. For more relevant Go collection content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!