Uğur Özyılmazel — — Filed under development reading time: 1 minutes

Unintended variable shadowing

In golang, you need to be careful while declaring your variables for re-using.

If you declare a variable in a block and re-declare in an inner block, you will face the variable shadowing situation! Let’s see what I mean;

package main

import (
    "fmt"
    "time"
)

func getFunnyName() string {
    return "jambalaya"
}

func main() {
    var name string // declare name
    name = "none"

    if time.Now().Year() > 1984 {
        // this is totally different variable
        // in an inner block and shadows
        // var name string
        name := getFunnyName()

        // name jambalaya
        fmt.Println("name", name)
    } else {
        fmt.Println("name", name)
    }

    // name final value none
    fmt.Println("name final value", name)
}

as you see, name := getFunnyName() is in the inner block and totally different declaration. It has nothing to do with var name string.

How do we fix that? First we need to check shadow issues via go vet. You need to install;

go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest

then you need to run it over your code;

go vet -vettool=$(command -v shadow) main.go 
# command-line-arguments
./main.go:20:3: declaration of "name" shadows declaration at line 13

Yep! here it is, you catch the bug! now, it’s time to fix the code;

package main

import (
    "fmt"
    "time"
)

func getFunnyName() string {
    return "jambalaya"
}

func main() {
    var name string // declare name
    name = "none"

    if time.Now().Year() > 1984 {
         // this set real name value
        name = getFunnyName()

        // name jambalaya
        fmt.Println("name", name)
    } else {
        fmt.Println("name", name)
    }

    // name final value jambalaya
    fmt.Println("name final value", name)
}

always keep this in mind, whenever you write if blocks or ; in your checks such as;

if variable := expression; variable != nil {
    // do your thing...
}

this means everything happens in your defined block scope!

Related Posts

Struct field alignment in golang

Inject values at build time

Network Addresses and Named Ports

Argument reuse

Better tool for listing virtual environments


Lastest Posts

Struct field alignment in golang

Inject values at build time

Static Sites with mkdocs and GitHub Pages

fancy console logger + inspector

Network Addresses and Named Ports