Go LRU Cache

A generic, fixed-capacity LRU cache for Go, built on a generic doubly linked list.
lru — a fixed-capacity cache with a least recently used eviction policy, safe for concurrent use.
list — the generic doubly linked list the cache is built on, usable on its own.
Requirements
Go 1.22 or newer.
Installation
go get github.com/mrLexx/go-cache
Usage
package main
import (
"fmt"
"github.com/mrLexx/go-cache/lru"
)
func main() {
cache := lru.MustNew[string, int](128)
cache.Set("a", 1)
cache.Set("b", 2)
value, ok := cache.Get("a")
fmt.Println(value, ok) // 1 true
value, ok = cache.Get("missing")
fmt.Println(value, ok) // 0 false
}
MustNew panics on an invalid capacity, which suits package-level variables and tests. Elsewhere, use New and handle the error:
cache, err := lru.New[string, int](128)
if err != nil {
return fmt.Errorf("create cache: %w", err)
}
The capacity must be in the range [1, 1024]. Outside it, New returns an error wrapping ErrInvalidCapacity:
_, err := lru.New[string, int](0)
fmt.Println(errors.Is(err, lru.ErrInvalidCapacity)) // true
Eviction
Once the cache is full, storing a new key drops the least recently used entry. Both Get and Set count as a use, so reading a key protects it from the next eviction:
cache := lru.MustNew[string, int](2)
cache.Set("a", 1)
cache.Set("b", 2)
cache.Get("a") // "a" is now the most recently used
cache.Set("c", 3) // evicts "b", not "a"
Storing a key that is already present overwrites its value and evicts nothing. Set reports whether the key was there before, and Clear empties the cache while keeping it usable with its original capacity.
The list package
list is a plain generic doubly linked list and does not depend on the cache:
l := list.New[string]()
l.PushBack("b")
l.PushBack("c")
first := l.PushFront("a") // a, b, c
l.MoveToFront(l.Back()) // c, a, b
l.Remove(first) // c, b
for item := l.Front(); item != nil; item = item.Next {
fmt.Println(item.Value)
}
Unlike Cache, a List is not safe for concurrent use; guard it yourself if several goroutines touch it.
Documentation
Full API documentation lives in the doc comments, most of it backed by runnable examples:
go doc github.com/mrLexx/go-cache/lru
go doc github.com/mrLexx/go-cache/list
Development
The project uses Task to automate building, testing and linting. It replaces the classic Makefile.
1. Installing Task
Install task on your machine before you begin.
The full list of installation methods is available in the official documentation.
2. Available commands
To list every available command with its description, run this in the project root:
task --list
Main development commands:
task bench — Runs benchmarks
task coverage:check — Checks coverage without running tests
task coverage:html — Generates an HTML coverage report
task deps:update — Updates dependencies
task docs — Updates the command list in README.md
task fix:apply — Applies automatic fixes (go fix)
task fix:diff — Previews automatic fixes as a diff (go fix -diff)
task format — Formats the code (gofumpt + gci)
task formatters:install — Installs gofumpt and gci
task golangci-lint:install — Installs golangci-lint
task install — Installs all tools
task lint — Runs golangci-lint
task test — Runs unit tests with the race detector
task test:coverage — Runs tests with coverage
task test:example — Runs Example tests