Skip to main content
Stack is a generic last-in, first-out (LIFO) data structure. The most recently pushed element is the first to be popped. The library provides four implementations that share a common interface, each with different allocation strategies.

Installation

import "github.com/fgm/container/stack"

Interface

type Stack[E any] interface {
    Push(E)
    Pop() (e E, ok bool)
}
MethodDescription
Push(e E)Places an element on top of the stack.
Pop() (e E, ok bool)Removes and returns the top element. If the stack is empty, returns the zero value of E and ok == false.

Constructors

All four constructors accept a sizeHint parameter and return container.Stack[E].
sizeHint
int
required
A non-binding hint for the initial capacity. Some implementations use it to pre-allocate storage; others ignore it. Pass 0 if you have no estimate.
s := stack.NewSliceStack[int](100)

Choosing an implementation

ConstructorBacking storeNotes
NewSliceStackGo sliceSimplest. Good default choice. sizeHint pre-allocates the slice.
NewListStackSingly-linked listNo pre-allocation; each element is a separate heap allocation.
NewListSyncPoolStackLinked list + sync.PoolPre-heats a sync.Pool with sizeHint nodes to reduce GC pressure under high throughput.
NewListInternalPoolStackLinked list + internal slice poolKeeps a bounded pool of recycled nodes inside the struct — no sync.Pool overhead. Best when allocation patterns are predictable.

Optional Countable interface

Some implementations also satisfy container.Countable, which adds a Len() method. Always check for it via a type assertion rather than relying on a specific implementation.
if c, ok := s.(container.Countable); ok {
    fmt.Printf("elements in stack: %d\n", c.Len())
}
Len() is not part of the core Stack interface because not all implementations provide it. Always guard the call with a type assertion as shown above.

Example

package main

import (
    "fmt"

    "github.com/fgm/container"
    "github.com/fgm/container/stack"
)

type Frame int

func main() {
    const sizeHint = 100
    s := stack.NewSliceStack[Frame](sizeHint)

    s.Push(Frame(1))
    s.Push(Frame(2))
    s.Push(Frame(3))

    // Optionally check the length if the implementation supports it.
    if c, ok := s.(container.Countable); ok {
        fmt.Printf("elements in stack: %d\n", c.Len())
    }

    // Drain the stack — LIFO order.
    for {
        e, ok := s.Pop()
        if !ok {
            break
        }
        fmt.Printf("popped: %v\n", e)
    }

    // Pop on an empty stack returns the zero value and ok=false.
    e, ok := s.Pop()
    fmt.Printf("empty pop -> value: %v, ok: %t\n", e, ok)
}
// Output:
// elements in stack: 3
// popped: 3
// popped: 2
// popped: 1
// empty pop -> value: 0, ok: false
Stack is not concurrency-safe. Do not share a Stack across goroutines without external synchronization.