Golang中关键字`var`的作用是什么?
Golang中关键字var的作用是什么?
var i int
var i = 10
var i,j = 10, 11
为什么不能直接写成…
i int
i :=10 // 在函数/方法外部 -- 希望 i 能自动推断为 int 类型。
i,j := 10, 11
我理解,本来可以写成 i, j = 10, 11,但是通过使用 :=,我们区分了通用的“等于”和自动类型推断。然而,我认为关键字 var 看起来是多余的,没有被 const 限定的东西本身就意味着它们是可以改变的。
此外,为什么 Go 不允许在函数/方法体外部进行像 i:=10 这样的自动类型推断呢?
更多关于Golang中关键字`var`的作用是什么?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
var允许直接指定类型。有时你会需要这样做。
你所说的“直接指定类型”是什么意思?
NobbZ:
你给出的确切示例可以从两个角度来看待
如果是为了解析的目的,我可以接受。你指的是哪个示例?
hollowaykeanho: what exactly is data? a constant or variable
varearly declaration makes a lot sense
你还是没明白,不过,还是谢谢你的时间。
为什么我们需要
var data *SomeLargeDataStruct而不是data *SomeLargeDataStruct
解析器的明确性。
var data *SomeLargeDataStruct
我们可以避免解析器在缺少 var 关键字时混淆乘法与声明,然而使用 var 似乎是一种简单有效的方法——这是出于性能的考虑。
如果你允许不使用 var 进行隐式变量声明,那么你给出的确切示例可以从两种角度来理解。
它既可以被视为乘法,也可以被视为声明。因此,这是为了在解析器中消除歧义。仅此而已。
你现在看不到它,因为你当前的用例和逻辑
恐怕你没有理解我简单的逻辑,我的整个问题是,为什么我们需要 var data *SomeLargeDataStruct 而不是 data *SomeLargeDataStruct。
附注:我把这个问题带到了 Go 的 Slack 频道,一些朋友似乎建议关键字 var 是为了“解析器优化”。
正如 @NobbZ 所说(甚至你自己看也能发现),
data到底是什么?是一个常量还是一个变量?
请记住,你可以在函数内部声明和初始化
const,尽管这种用例很少见。
正如我所说,你现在看到的例子太简单了。一旦你接触到内存指针并处理大型数据结构或资源消耗大的函数时,提前使用
var声明就非常有意义,因为你希望统计变量的总使用量以优化内存消耗。
甚至有一种观点认为,一个函数使用的变量超过 12 个,就自然表明该函数需要简化,主要是因为我们人类一次大约只能跟踪 12 个变量。这是一种观点。
说到简单,也是因为为每个简单的变量都提前声明太繁琐,这就是 Go 决定为这种用例创建
:=关键字的原因。
然而,我认为关键字
var看起来是多余的,没有被const限定的东西隐含地意味着它们可以被改变。
两个原因:
- 主观偏好(例如,变量计数实践)
- 用于延迟初始化。
你现在看不到这一点,因为你当前的用例和逻辑非常简单,不需要它。如果我们有一个结构体类型,比如说包含兆字节大小的数据结构,并且初始化值无法保证,你会希望延迟初始化它。考虑以下情况:
func GetData(query string) {
var data *SomeLargeDataStruct // data = nil
... 做一些不需要数据的工作 ... // data = nil
... 经过 N 个周期后 ... // data = nil
... 天啊,处理起来真费劲 ... // data = nil
data = GetFromDatabase(query) // data = 兆字节 或者 data = nil
if data == nil { // data = 兆字节 或者 data = nil
return // data = nil
}
... 用数据做一些工作 ... // data* = 兆字节
}
- 正如我在函数开头声明的,我将占用大量内存(变量计数),这向其他开发者清楚地表明,这个函数将在某个时刻使用会消耗大量内存的
data。 - 请注意,当我不从一开始就使用数据,并且查询失败时,我不需要给我的程序内存消耗增加负担。只有当我查询它并想要处理它时,它才会占用数据。
为什么 Go 不允许在函数/方法体之外进行自动类型推导,比如
i:=10。
因为它们是特定的和冗余的。就像,你有你的常量和变量组可供使用?
const (
...
)
var (
...
)
在Go语言中,var关键字用于声明变量,其作用包括:
- 显式声明变量类型:
var i int // 声明int类型变量i
var s string // 声明string类型变量s
- 声明并初始化(类型推断):
var i = 10 // 编译器推断i为int类型
var name = "Go" // 编译器推断name为string类型
- 批量声明变量:
var (
x int
y = 20
z = "hello"
)
- 声明零值变量:
var n int // n初始化为0
var str string // str初始化为""
var b bool // b初始化为false
关于为什么不能在包级别使用:=:
技术原因:
// 包级别必须使用var
package main
var globalVar = 100 // 正确
// globalVar2 := 200 // 编译错误:syntax error: non-declaration statement outside function body
func main() {
localVar := 300 // 正确,函数内部可以使用:=
}
设计哲学:
- 作用域明确性:包级别变量具有全局可见性,需要更明确的声明方式
- 初始化时机控制:
var (
// 包级别变量在main函数执行前初始化
startTime = time.Now()
config = loadConfig()
)
func loadConfig() string {
return "config data"
}
- 与短变量声明的区别:
func example() {
// := 是声明+初始化的简写,只能用于函数内部
x := 10 // 等价于 var x = 10
// 重新声明
y, x := 20, 30 // 允许,x被重新赋值
// var 允许后续赋值
var z int
z = 40
}
- 常量声明的对称性:
const Pi = 3.14159 // const用于常量
var radius = 5.0 // var用于变量
实际使用示例:
package main
import "fmt"
// 包级别变量声明
var (
appVersion = "1.0.0"
debugMode = false
maxRetries = 3
)
// 使用var进行类型明确的声明
var connectionTimeout int = 30
func main() {
// 函数内部可以使用:=
localCount := 0
msg := "Hello"
// 多变量声明
var a, b, c = 1, 2.0, "three"
fmt.Println(appVersion, localCount, a, b, c)
// := 的重新声明特性
x := 10
{
x, y := 20, 30 // 新的作用域,x被重新声明
fmt.Println(x, y) // 输出: 20 30
}
fmt.Println(x) // 输出: 10
}
这种设计保持了语言的一致性:var用于变量声明,const用于常量声明,:=作为函数内部的语法糖。包级别的自动类型推断仍然可以通过var实现,如var i = 10,但需要显式的var关键字来区分声明语句和其他语句。


