Golang新手问题:变量初始化的方法与技巧
Golang新手问题:变量初始化的方法与技巧 大家好,我正在学习Golang,有个问题想请教。
这是一个简单的测试程序代码:
package main
import ("fmt"
)
var (
john string
mike string
c = "dce"
)
func main() {
john := "john"
c = "A"
c := "B"
i := 10
fmt.Println("i",i,john,c)
c := "C"
}
请注意变量’c’。 我先给它赋值为"A",然后使用:=运算符声明并设置为"B" 代码运行没有任何错误,但当我再次使用:=将其设置为"C"时,Golang就会报错。 难道在尝试将其设置为"B"时不应该报错吗?因为c已经被赋值过了。
我原以为:=只在变量尚未初始化时使用,所以产生了这个疑问。
更多关于Golang新手问题:变量初始化的方法与技巧的实战教程也可以访问 https://www.itying.com/category-94-b0.html
感谢 @NoobZ 和 @Yamil_Bracho 的回复!
更多关于Golang新手问题:变量初始化的方法与技巧的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
:= 只有在当前作用域中已存在该变量时才会失效,但它会遮蔽来自更大/外部作用域的变量。
霍利韦,
非常感谢!这解释并解决了我的问题!也非常感谢您提供的示例代码,让我一步步理解……我现在变得更好了 :-)。
好的,但我觉得这有点奇怪。我认为不管变量是全局还是局部的,根据 := 的定义,编译器应该报错才对,你不觉得吗?不确定允许这种情况发生有什么好处……
“:=” 用于声明并初始化变量,它仅在函数作用域内有效。
因此,如果你这样写:
var a bool = true
等同于这样写:
a := true
非常感谢!这解释并解决了我的问题!同时也非常感激您提供的示例代码,让我能够逐步理解……我现在进步了很多 :-)。
不客气!记得也要感谢 @NobbZ 和 @Yamil_Bracho!在结束之前:
欢迎来到 Golang Bridge!🚀🎆
NobbZ:
只有当变量在当前作用域中已存在时,
:=才会报错,但它会遮蔽来自更大/外部作用域的变量。
howardyoo:
好吧,但这有点奇怪,我认为无论变量来自全局还是局部作用域,根据
:=的定义,编译器都应该报错,你不觉得吗?不确定允许这种情况发生有什么好处…
简单来说,你遇到了使用全局变量的后果。在 Go 语言中,允许声明与全局变量同名的局部变量,但会失去访问对应全局变量的能力。
参考以下代码:
package main
import (
"fmt"
)
var (
a = "Hello"
b = "World"
)
func globalCheck() {
fmt.Printf("GLOBAL: %v %v\n", a, b)
}
func main() {
fmt.Printf("AFTER : %v %v\n", a, b)
globalCheck()
}
// 输出:
// AFTER : Hello World
// GLOBAL: Hello World
这里你访问的是两个全局变量。现在,在 main 函数内部,我们声明另一个局部变量 a:
package main
import (
"fmt"
)
var (
a = "Hello"
b = "World"
)
func globalCheck() {
fmt.Printf("GLOBAL: %v %v\n", a, b)
}
func main() {
a := "Bonjour"
fmt.Printf("AFTER : %v %v\n", a, b)
globalCheck()
}
// 输出:
// AFTER : Bonjour World
// GLOBAL: Hello World
如果在 main 函数中修改变量 a,你设置的是局部版本:
package main
import (
"fmt"
)
var (
a = "Hello"
b = "World"
)
func globalCheck() {
fmt.Printf("GLOBAL: %v %v\n", a, b)
}
func main() {
a := "Bonjour"
fmt.Printf("BEFORE: %v %v\n", a, b)
a = "你好"
fmt.Printf("AFTER : %v %v\n", a, b)
globalCheck()
}
// 输出:
// BEFORE: Bonjour World
// AFTER : 你好 World
// GLOBAL: Hello World
因此,如果在 main 函数内部声明局部变量 a 后再次使用 := 运算符,会导致编译错误,提示 a 已存在:
package main
import (
"fmt"
)
var (
a = "Hello"
b = "World"
)
func globalCheck() {
fmt.Printf("GLOBAL: %v %v\n", a, b)
}
func main() {
a := "Bonjour"
fmt.Printf("BEFORE: %v %v\n", a, b)
a := "你好"
fmt.Printf("AFTER : %v %v\n", a, b)
globalCheck()
}
// 输出:
// # command-line-arguments
// ./main.go:19:4: no new variables on left side of :=
如何重新访问全局变量
- 首先不要使用全局变量(推荐)
- 避免命名冲突。注意你无法阻止使用者重复这个问题
- 使用 setter/getter 函数。例如
globalCheck()就是一个 getter 函数
在您的代码中,变量 c 的行为涉及 Go 语言中变量声明和短变量声明(:=)的作用域规则。让我们逐步分析:
-
全局变量
c:- 在包级别,
var c = "dce"声明了一个全局变量c,初始值为"dce"。 - 全局变量在包内所有函数中可见。
- 在包级别,
-
在
main函数内:c = "A":这是对全局变量c的赋值,将值从"dce"改为"A"。c := "B":这里使用短变量声明:=。在 Go 中,:=会声明一个新变量,如果当前作用域内已有同名变量,它会创建一个新的局部变量,隐藏外部变量。因此,这一行声明了一个新的局部变量c,初始化为"B",并隐藏了全局变量c。c := "C":当您再次使用:=声明c时,由于局部变量c已在上一步声明(通过c := "B"),在同一作用域内重复声明会导致编译错误。Go 不允许在同一作用域内重复声明变量(使用:=或其他方式)。
关键点:
- 短变量声明
:=仅在变量在当前作用域内未声明时才用于声明新变量。如果变量已存在,:=会尝试重新声明,但仅当至少有一个新变量被声明时才允许(即左侧变量列表中至少有一个是新的)。在您的代码中,c := "C"没有新变量,因此报错。 - 在
c := "B"时没有报错,因为它创建了一个新局部变量,隐藏了全局c。但c := "C"在同一作用域内重复声明同一变量,违反了规则。
示例代码解释: 这是您的代码简化后,展示作用域问题:
package main
import "fmt"
var c = "dce" // 全局变量
func main() {
c = "A" // 赋值给全局变量 c
fmt.Println(c) // 输出 "A"
c := "B" // 声明新局部变量 c,隐藏全局 c
fmt.Println(c) // 输出 "B"
// c := "C" // 如果取消注释,会报错:no new variables on left side of :=
// 因为 c 已在同一作用域声明
// 要修改局部 c,直接赋值:
c = "C" // 正确:赋值给局部变量 c
fmt.Println(c) // 输出 "C"
}
输出:
A
B
C
总结:
- 使用
:=时,确保在当前作用域内没有重复声明同一变量。 - 如果变量已存在,使用简单赋值
=来修改值。 - 全局变量和局部变量可能因作用域隐藏而表现不同;使用短变量声明时要小心作用域变化。
在您的原始代码中,c := "B" 是允许的,因为它引入了新局部变量,但 c := "C" 在同一块中重复声明,导致错误。修正方法是使用 c = "C" 进行赋值。

