Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 25 additions & 23 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.22.x', '1.23.x', '1.24.x', '1.25.x']
go-version: ['1.18.x', '1.19.x', '1.20.x', '1.21.x', '1.22.x', '1.23.x', '1.24.x', '1.25.x']

steps:
- name: Checkout code
Expand All @@ -29,36 +29,38 @@ jobs:
run: go mod download

- name: Run tests
run: go test -v -race ./...

- name: Run tests with coverage (Go 1.23 only)
if: matrix.go-version == '1.23.x'
run: go test -v -race -coverprofile=coverage.out ./...

- name: Upload coverage
uses: codecov/codecov-action@v4
if: matrix.go-version == '1.25.x'
if: matrix.go-version == '1.23.x'
with:
file: ./coverage.out
flags: unittests
fail_ci_if_error: false

# lint:
# name: Lint
# runs-on: ubuntu-latest
# # Skipped for now - golangci-lint doesn't support Go 1.25 yet
# # Will re-enable once golangci-lint releases a version built with Go 1.25
# steps:
# - name: Checkout code
# uses: actions/checkout@v4
#
# - name: Set up Go
# uses: actions/setup-go@v5
# with:
# go-version: '1.24.x'
# cache: true
#
# - name: golangci-lint
# uses: golangci/golangci-lint-action@v6
# with:
# version: latest
# args: --timeout=5m
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.23.x'
cache: true

- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: latest
args: --timeout=5m

build:
name: Build
Expand All @@ -71,7 +73,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25.x'
go-version: '1.23.x'
cache: true

- name: Build
Expand Down
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ run:
timeout: 5m
tests: true
modules-download-mode: readonly
go: '1.18'

linters:
enable:
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/anish749/lazy

go 1.25
go 1.18
12 changes: 9 additions & 3 deletions lazy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import "sync"
// Lazy represents a value that is initialized on first access.
// It ensures the initialization function is called only once, even in concurrent scenarios.
type Lazy[T any, E error] struct {
once sync.Once
value T
err E
init func() (T, E)
once sync.Once
}

// NewLazy creates a new lazy value with the provided initialization function.
Expand All @@ -29,14 +29,20 @@ func InitializedLazy[T any, E error](value T) *Lazy[T, E] {
}
}

func (l *Lazy[T, E]) Get() (T, E) {
// Get retrieves the lazy value, initializing it on first call if needed.
// The initialization function is guaranteed to be called at most once,
// even when Get is called concurrently from multiple goroutines.
// Returns the computed value and any error from initialization.
func (l *Lazy[T, E]) Get() (value T, err E) {
// Skip once.Do if init is nil, meaning the value was pre-initialized
if l.init != nil {
l.once.Do(func() {
l.value, l.err = l.init()
})
}
return l.value, l.err
value = l.value
err = l.err
return
}

// lazyType is an interface constraint for lazy value getters
Expand Down
Loading