Import the queue sub-package and create a slice-backed queue with a size hint.
package mainimport ( "fmt" "github.com/fgm/container" "github.com/fgm/container/queue")type Element int// sizeHint is an indication of the maximum number of elements expected.// It is not a hard limit — implementations may use it to pre-allocate storage.const sizeHint = 100func main() { var e Element = 42 q := queue.NewSliceQueue[Element](sizeHint) q.Enqueue(e) // Check length if the implementation supports it. if lq, ok := q.(container.Countable); ok { fmt.Printf("elements in queue: %d\n", lq.Len()) } // Dequeue returns the element and a boolean indicating success. for i := 0; i < 2; i++ { e, ok := q.Dequeue() fmt.Printf("Element: %v, ok: %t\n", e, ok) }}
Output:
elements in queue: 1Element: 42, ok: trueElement: 0, ok: false
The second Dequeue returns the zero value and ok: false because the queue is empty. Always check ok before using the returned element.
3
Use a Stack
Import the stack sub-package. The API mirrors the queue — Push and Pop instead of Enqueue and Dequeue.
import "github.com/fgm/container/stack"s := stack.NewSliceStack[Element](sizeHint)s.Push(e)if ls, ok := s.(container.Countable); ok { fmt.Printf("elements in stack: %d\n", ls.Len())}for i := 0; i < 2; i++ { e, ok := s.Pop() fmt.Printf("Element: %v, ok: %t\n", e, ok)}
Output:
elements in stack: 1Element: 42, ok: trueElement: 0, ok: false
4
Use a Set
Import the set sub-package. Set eliminates duplicates and supports standard set operations.
import ( "fmt" "github.com/fgm/container" "github.com/fgm/container/set")func main() { var e Element = 42 s := set.NewBasicMap[Element](sizeHint) // Add the squares of 0..41 to the set. for i := range e { s.Add(i * i) } if cs, ok := s.(container.Countable); ok { fmt.Printf("elements in set: %d\n", cs.Len()) } // Remove elements — Remove is safe to call even for absent items. for i := Element(0); i < 10; i++ { del := i * i * i ok := s.Remove(del) fmt.Printf("Element: %3v ok: %t\n", del, ok) }}
5
Use a WaitableQueue for concurrent code
WaitableQueue is the only concurrency-safe type in the module. It uses a WaitChan to signal consumers when items are available, avoiding the capacity constraints of Go channels.
package mainimport ( "fmt" "time" "github.com/fgm/container" "github.com/fgm/container/queue")type Element intfunc consumer(wq container.WaitableQueue[Element]) { lq := wq.(container.Countable) for { _, ok := <-wq.WaitChan() if !ok { fmt.Printf("Consumer exiting, %d remaining\n", lq.Len()) return } for { item, ok, _ := wq.Dequeue() if !ok { break } fmt.Printf("Received: %v, %d in queue\n", item, lq.Len()) } }}func main() { const sizeHint, low, high = 200, 50, 150 wq, err := queue.NewWaitableQueue[Element](sizeHint, low, high) if err != nil { panic(err) } go consumer(wq) for i := range 10 { wq.Enqueue(Element(i)) time.Sleep(2 * time.Millisecond) } wq.Close() // Unblocks consumers waiting on WaitChan. time.Sleep(50 * time.Millisecond)}
Call Close() on the queue when the producer is done. This unblocks any consumers that are waiting on WaitChan, allowing them to drain remaining items and exit cleanly.
Every constructor accepts a sizeHint argument. This is a hint — not a hard cap — that slice-backed implementations use to pre-allocate storage and avoid repeated resizing: