Where can we use Variable Scoping and Shadowing in Go?

huangapple go评论84阅读模式
英文:

Where can we use Variable Scoping and Shadowing in Go?

问题

我找到了一些相关的帖子:

此外,变量作用域和变量遮蔽有许多用例。
如果有任何代码示例或答案,将不胜感激。

英文:

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

得分: 5

变量作用域和遮蔽:

  • Go语言使用块进行词法作用域:

    1. 预声明标识符的作用域是全局块。
    2. 声明在顶层(任何函数外部)的常量、类型、变量或函数(但不包括方法)的标识符的作用域是包块。
    3. 导入包的包名的作用域是包含导入声明的文件块。
    4. 方法接收器、函数参数或结果变量的标识符的作用域是函数体。
    5. 在函数内部声明的常量或变量标识符的作用域从ConstSpec或VarSpec(对于短变量声明为ShortVarDecl)的结束开始,直到最内层包含块的结束。
    6. 在函数内部声明的类型标识符的作用域从TypeSpec中的标识符开始,直到最内层包含块的结束。
    7. 在块中声明的标识符可以在内部块中重新声明。在内部声明的标识符在作用域内时,它表示内部声明所声明的实体。
  • 包声明不是一个声明;包名不出现在任何作用域中。它的目的是标识属于同一包的文件,并指定导入声明的默认包名。

优点:

  • 由于无法从外部作用域访问数据,数据完整性得到保护。

Go语言中不同形式的变量遮蔽:

  1. 限制变量作用域的Go语言方式(在语句内使用简写赋值):
package main
import "fmt"
func main() {
    i := 10 //作用域:main
    j := 4
    for i := 'a'; i < 'b'; i++ {
        // 在此块内部遮蔽了i
        fmt.Println(i, j) //97 4
    }
    fmt.Println(i, j) //10 4

    if i := "test"; len(i) == j {
        // 在此块内部遮蔽了i
        fmt.Println(i, j) // i= test , j= 4
    } else {
        // 在此块内部遮蔽了i
        fmt.Println(i, j) //test 40
    }
    fmt.Println(i, j) //10 4
}
  1. 当"我们需要更多字母"时,这是一种很好的限制变量作用域的方式。
    这也适用于需要更多局部变量或作用域的情况:

    使用{}配对:
    优点:无需额外的if、for等语句。

package main
import "fmt"
func main() {
    i := 1
    j := 2
    // 新的作用域:
    {
        i := "hi" //新的局部变量
        j++
        fmt.Println(i, j) //hi 3
    }
    fmt.Println(i, j) //1 3
}
  1. 另一种限制变量作用域的方式是使用函数调用:
    优点:作用域限制,输入值类型参数可像局部变量一样使用。
    缺点:调用/返回时间和堆栈使用:如果编译器没有进行优化。
package main
import "fmt"
func fun(i int, j *int) {
    i++                //+nice: 作为局部变量使用,没有副作用
    *j++               //+nice: 故意作为全局变量使用
    fmt.Println(i, *j) //11 21
}
func main() {
    i := 10 //作用域:main
    j := 20
    fun(i, &j)
    fmt.Println(i, j) //10 21
}
  1. 另一种方式是遮蔽全局变量:
package main
import "fmt"
var i int = 1 //全局变量
func main() {
    j := 2
    fmt.Println(i, j) //1 2
    i := 10           //遮蔽全局变量
    fmt.Println(i, j) //10 2
    fun(i, j)         //10 2
}
func fun(i, j int) {
    //i := 100        //错误::=左侧没有新的变量
    //var i int = 100 //错误:在此块中重新声明了i
    fmt.Println(i, j) //10 2
}

参考:Variable shadowingScope
以及:Declarations and scope

英文:

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):

    <!-- language: lang-golang -->

     package main
     import &quot;fmt&quot;
     func main() {
     	i := 10 //scope: main
         j := 4
     	for i := &#39;a&#39;; i &lt; &#39;b&#39;; i++ {
             // i shadowed inside this block
         	fmt.Println(i, j) //97 4
     	}
     	fmt.Println(i, j) //10 4
    
         if i := &quot;test&quot;; 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, …

    <!-- language: lang-golang -->

     package main
     import &quot;fmt&quot;
     func main() {
     	i := 1
         j := 2
     	//new scope :
     	{
     		i := &quot;hi&quot; //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

    <!-- language: lang-golang -->

     package main
     import &quot;fmt&quot;
     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, &amp;j)
     	fmt.Println(i, j) //10 21
     }
    
  4. Another way is shadowing global variables:

    <!-- language: lang-golang -->

     package main
     import &quot;fmt&quot;
     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:

huangapple
  • 本文由 发表于 2016年4月11日 23:37:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/36553134.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定