在不同范围内使用多个同名变量是否有合理的用例?

以下(设计的)代码定义了变量 i 的两次出现或“实例”:


import "fmt"


func main() {

    goto_done := false

    i := 3

fred:

    fmt.Printf("i #1 = %d\n", i)

    if !goto_done {

        i := 4

        fmt.Printf("i #2 = %d\n", i)

        goto_done = true

        goto fred

    }

}

从输出中可以看出,这两个值都作为单独的值存在,因为定义第二个值不会覆盖第一个值:


i #1 = 3

i #2 = 4

i #1 = 3

此功能是否有任何建设性的用例,或者它只是语言的一个怪癖?


海绵宝宝撒
浏览 48回答 1
1回答

慕仙森

以下是一些用例:1.关闭Go 有闭包,这意味着你可以创建一个引用封闭变量的匿名函数。闭包有很多很好的用途,但这意味着匿名函数会继承它们的封闭变量名。err := trySomething()workChan := make(chan work)// start a workergo func() {&nbsp; &nbsp; // we're using the existing workChan from the enclosing scope&nbsp; &nbsp; for job := range workChan {&nbsp; &nbsp; &nbsp; &nbsp; //&nbsp; vv this is name shadowing! (we're shadowing the existing err)&nbsp; &nbsp; &nbsp; &nbsp; err := do(job)&nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; logError(err)&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}()err = tryAnotherThing()if err != nil {&nbsp; &nbsp; return err}如果我们不能隐藏名称,那么工作线程和主线程将竞争使用同一个err变量(导致未定义的行为)。因此,您可以感谢阴影,因为您不必键入err2、errr等。2. 在封闭范围内添加新名称假设你有一个现有的包,你想添加一个新的全局常量或变量,名为gopher. 您不想搜索整个包源中的每个范围以查看该名称gopher是否已在任何地方使用。在Go 1.18版本中,添加了两个新的预声明标识符:any和comparable。由于允许名称隐藏,因此可以将像这样的通用标识符添加到 Go 而不会破坏以前正确的 Go 程序(另请参见Go 1 兼容性声明)3.粘贴代码Shadowing 允许您像这样复制和粘贴“自包含”代码,并使其在您放置的任何地方(几乎)都能正常工作。// Print Fibonacci numbersfor i, j := 0, 1; j < 100; i, j = j, i+j {&nbsp; &nbsp; fmt.Println(j)}i并且j是非常常见的变量名称,因此如果不允许隐藏,则如果您尝试将其粘贴到代码中的某处,很可能会发生冲突,从而导致错误。当然,通常最好避免隐藏,因为它会导致意想不到的错误并降低代码的可读性(尤其是在没有 IDE 中可能会出现的范围感知突出显示的情况下)。在更长、更现实的场景中,您可能想要重命名您可能粘贴的任何阴影名称。值得庆幸的是,阴影在语言中是有效的,它实际上应该更容易重命名它们:由于i和j是有效且不同的变量,一个好的 IDE 应该允许您像对待任何其他变量一样快速重命名这些变量及其所有用法。
打开App,查看更多内容
随时随地看视频慕课网APP