Golang中变量作用域详解

Golang中变量作用域详解 我正在阅读一本名为《Go 编程语言》的书籍。其中有一节解释了变量的作用域。我很难理解链接中代码的运行原理。请帮我理解这个问题。提前感谢!!

程序可以在这里找到:https://play.golang.org/p/X2INlbJK1JP

8 回复

我会记住这一点的!感谢指出。

更多关于Golang中变量作用域详解的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢分享这份资源 🙂

// 代码示例保留原样

感谢您的回复。现在清楚了。表情符号

阿什温, 请注意,你发布的这段代码示例存在被称为变量遮蔽的问题,这在 Go 语言中是不被推荐的。

当外部作用域中的变量与内部作用域中的变量同名时,就会发生这种情况,这可能会让不熟悉代码的人感到困惑。

变量遮蔽

在计算机编程中,当在某个作用域(决策块、方法或内部类)内声明的变量与外部作用域中声明的变量同名时,就会发生变量遮蔽。在标识符(名称而非变量)级别,这被称为名称屏蔽。外部变量被称为被内部变量遮蔽,而内部标识符被称为屏蔽外部标识符。这可能会导致混淆,因为后续使用中不清楚是哪个变量…

此致。

引用自 如何在本论坛发布代码 [网站反馈]

在本论坛发布代码时,强烈建议采用以下方式之一:

作为 Go Playground 链接 访问 https://play.golang.org 输入或粘贴代码。点击 Format 按钮获得规范格式,然后点击 Share 获取可复制到论坛的链接。

或使用代码块语法 在论坛中写入或粘贴代码时,使用两行 go 和(三个反引号)包裹代码。例如:

a := b + c
Fmt.Println("Answer is", a)

这样代码就会美观地显示出来…

阿什温,让我们逐行分析。

首先,约翰的建议很对,应该把代码发到这个论坛上。至少在你读完他的消息后要这么做。 这样我们能更高效、更准确地进行解释。

深入这段代码,它会对字符串中的每个字母进行大写转换。 我猜你是在问为什么

x := "hello!"

x := x[i]

没有报错,尽管你多次对x进行赋值。 我的理解是,第二个x拥有与第一个变量x不同的指针(内存分配)。 从技术角度来说 至少这是我的观点,如果我有说错的地方,欢迎大家指正。但埃里克的回答确实一针见血。

此致,

每个花括号 { 都会创建一个新的代码块(或称为作用域)。任何在代码块中声明的变量都将属于该代码块。

因此,
x := "hello!" 属于 func main()。然而,内部代码块(例如 for 语句的代码块)也可以访问它。

for 语句中的 x := x[i] 属于该 for 语句。而 func main() 无法看到这个新的声明。

最后,if 语句中的 x := x + 'A' - 'a' 属于该 if 语句。无论是 for 语句还是 main 函数都无法访问它。这是因为它是在最内层代码块中声明的。然而,该 if 语句本可以看到之前的 x 声明,但它声明了一个新的 x,因此它也无法访问之前的 x。

在Go语言中,变量的作用域决定了变量在代码中的可见性和生命周期。根据你提供的代码链接(https://play.golang.org/p/X2INlbJK1JP),我来解释一下变量作用域的关键点,并提供一个示例来阐明这个概念。

在Go中,变量的作用域主要分为:

  • 局部作用域:变量在函数、循环或块(如if语句)内部声明,仅在该范围内可见。
  • 包级作用域:变量在函数外部声明,对整个包可见。
  • 全局作用域:如果变量以大写字母开头,它可以从其他包访问。

从你链接的代码来看,它可能涉及嵌套作用域或变量遮蔽(variable shadowing),即内部作用域中声明的变量会遮蔽外部作用域的同名变量。这可能导致意外行为,尤其是在使用短变量声明(:=)时。

以下是一个简单的示例代码,演示了变量作用域和遮蔽现象:

package main

import "fmt"

var globalVar = "I am global" // 包级作用域,对整个包可见

func main() {
    localVar := "I am local in main" // 局部作用域,仅在main函数内可见
    fmt.Println("In main:")
    fmt.Println("globalVar:", globalVar)
    fmt.Println("localVar:", localVar)

    // 在if块中声明同名变量,会遮蔽外部变量
    if true {
        localVar := "I am shadowed in if block" // 遮蔽了main中的localVar
        fmt.Println("In if block:")
        fmt.Println("localVar:", localVar) // 输出遮蔽后的值
        fmt.Println("globalVar:", globalVar) // 全局变量不受影响
    }

    // 离开if块后,遮蔽的变量不再可见,恢复为main中的localVar
    fmt.Println("After if block:")
    fmt.Println("localVar:", localVar)

    // 调用另一个函数,演示函数级作用域
    anotherFunction()
}

func anotherFunction() {
    // 这里无法访问main中的localVar,因为它是局部变量
    fmt.Println("In anotherFunction:")
    fmt.Println("globalVar:", globalVar) // 可以访问全局变量
    // fmt.Println(localVar) // 这行会编译错误:undefined: localVar
}

运行此代码的输出将是:

In main:
globalVar: I am global
localVar: I am local in main
In if block:
localVar: I am shadowed in if block
globalVar: I am global
After if block:
localVar: I am local in main
In anotherFunction:
globalVar: I am global

关键点:

  • main函数中声明的localVar是局部变量,仅在main内可见。
  • if块中使用:=重新声明localVar会创建一个新变量,遮蔽了外部的localVar,但只在if块内有效。
  • 全局变量globalVar在整个包中可见,包括所有函数。
  • 每个函数都有自己的作用域,无法直接访问其他函数的局部变量。

如果你链接的代码涉及更复杂的场景(如闭包或嵌套函数),请分享具体代码片段,我可以进一步分析。理解作用域有助于避免变量冲突和编写可维护的代码。

回到顶部