Where can we use Variable Scoping and Shadowing in

2020-02-01 06:55发布

Some related posts I've found:

Also there are many use cases to Variable Scoping and Shadowing.
Any code samples or answers will be appreciated.

1条回答
狗以群分
2楼-- · 2020-02-01 07:22

Variable scoping and shadowing:

Go is lexically scoped using blocks:

  1. The scope of a predeclared identifier is the universe block.
  2. The scope of an identifier denoting a constant, type, variable, or function (but not method) declared at top level (outside any function) is the package block.
  3. The scope of the package name of an imported package is the file block of the file containing the import declaration.
  4. The scope of an identifier denoting a method receiver, function parameter, or result variable is the function body.
  5. The scope of a constant or variable identifier declared inside a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl for short variable declarations) and ends at the end of the innermost containing block.
  6. The scope of a type identifier declared inside a function begins at the identifier in the TypeSpec and ends at the end of the innermost containing block.
    An identifier declared in a block may be redeclared in an inner block.
    While the identifier of the inner declaration is in scope, it denotes the entity declared by the inner declaration.

The package clause is not a declaration; the package name does not appear in any scope. Its purpose is to identify the files belonging to the same package and to specify the default package name for import declarations.

Advantages:

  • Since data cannot be accessed from outer scope, Data Integrity is preserved

Different forms of Variable shadowing in Go:

  1. Golang way to limit variable scope (using short-hand assignment inside statements):

    package main
    import "fmt"
    func main() {
        i := 10 //scope: main
        j := 4
        for i := 'a'; i < 'b'; i++ {
            // i shadowed inside this block
            fmt.Println(i, j) //97 4
        }
        fmt.Println(i, j) //10 4
    
        if i := "test"; len(i) == j {
            // i shadowed inside this block
            fmt.Println(i, j) // i= test , j= 4
        } else {
            // i shadowed inside this block
            fmt.Println(i, j) //test 40
        }
        fmt.Println(i, j) //10 4
    }
    
  2. When "we need more alphabets", this is nice way to limit variables scope.
    Also this works well when you need more local variables or scope:

    using { and } pair:
    Pros: no need to extra statements like if, for, …

    package main
    import "fmt"
    func main() {
        i := 1
        j := 2
        //new scope :
        {
            i := "hi" //new local var
            j++
            fmt.Println(i, j) //hi 3
        }
        fmt.Println(i, j) //1 3
    }
    
  3. Another way to limit variable scope is using function calls:
    Pros: scope limit, input value type parameters are usable like local variables,
    Cons: call/return time, and stack usage: if it is not optimized by compiler

    package main
    import "fmt"
    func fun(i int, j *int) {
        i++                //+nice: use as local var without side effect
        *j++               //+nice: intentionally use as global var
        fmt.Println(i, *j) //11 21
    }
    func main() {
        i := 10 //scope: main
        j := 20
        fun(i, &j)
        fmt.Println(i, j) //10 21
    }
    
  4. Another way is shadowing global variables:

    package main
    import "fmt"
    var i int = 1 //global
    func main() {
        j := 2
        fmt.Println(i, j) //1 2
        i := 10           //Shadowing global var
        fmt.Println(i, j) //10 2
        fun(i, j)         //10 2
    }
    func fun(i, j int) {
        //i := 100        //error: no new variables on left side of :=
        //var i int = 100 //error: i redeclared in this block
        fmt.Println(i, j) //10 2
    }
    

See: Variable shadowing and Scope.
And: Declarations and scope:

查看更多
登录 后发表回答