diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 69b84cb..54c1113 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 @@ -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 @@ -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 diff --git a/.golangci.yml b/.golangci.yml index f9b5700..62a3e41 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -2,6 +2,7 @@ run: timeout: 5m tests: true modules-download-mode: readonly + go: '1.18' linters: enable: diff --git a/go.mod b/go.mod index 0c365ab..42b6280 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/anish749/lazy -go 1.25 +go 1.18 diff --git a/lazy.go b/lazy.go index d28ce96..280058b 100644 --- a/lazy.go +++ b/lazy.go @@ -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. @@ -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