Go

Explain variable shadowing. Find the bug in this code.

Question 6MediumGo 1.22 to 1.25
var db *sql.DB

func initDB() error {
	db, err := sql.Open("postgres", dsn) // BUG: declares a new local db
	if err != nil {
		return err
	}
	return db.Ping()
}
// Later: db.Query(...) panics with a nil pointer dereference

:= declares new variables in the current scope. Because db is not already declared in the function scope, := creates a local db that hides the package-level one. The package-level db stays nil. The fix is to declare err separately and use plain assignment:

func initDB() error {
	var err error
	db, err = sql.Open("postgres", dsn)
	if err != nil {
		return err
	}
	return db.Ping()
}

Tricky variant:

x := 1
if x := 2; x > 1 {
	fmt.Println(x) // 2
}
fmt.Println(x)     // 1

The init statement of if, for and switch opens its own block, so the inner x exists only there. Tools that catch shadowing: the shadow analyzer, which is not part of default go vet (install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow and run go vet -vettool=$(which shadow)), or golangci-lint with the govet linter's shadow check enabled.

More on Language Fundamentals & Types

All 39 Language Fundamentals & Types questions