Go :如何声明变量(var)与常量(const)

序言

🐒:

今天开始学习 Go 语言的 变量与常量,该文章会记录一些相关的知识点和案例。


变量

定义

用于存储程序运行时可改变的数据


声明方式

方式 语法 适用场景 示例
标准声明 var 变量名 类型 = 表达式 显式指定类型 或 需要零值初始化 var age int = 25
类型推断 var 变量名 = 表达式 省略类型,由右侧值推导 var age = 25
声明赋值 var 变量名 类型 变量名 = 表达式 省略类型,由右侧值推导先声明,后赋值 var age int age = 25
短变量声明 变量名 := 表达式 函数内部,最常用、最简洁 age := 25
多变量声明 var (变量1 类型1 = 值1 ...) var 变量1,变量2 = 值1,值2 ) 批量声明,常用于包级别 var (age int = 25; name string = "windy") var a, b = 1,2

示例:标准声明


go 复制代码
package main

import "fmt"

func main() {
	var age int = 25
	fmt.Println(age)
}
bash 复制代码
25

🐒:

这种声明方式虽然很清晰明了,但对我来说有点麻烦。代码敲多了的时候,是不会考虑这种,因为有点累脑费眼,所以优先于简洁的方式。


示例:类型推断


go 复制代码
package main

import "fmt"

func main() {
	var age = 25
	fmt.Println(age)
}
bash 复制代码
25

🐒:

这种声明方式相对于第一个来说简单了些,我一般用于全局变量(看情况进行初始化),例如存储验证码。


示例:声明赋值


go 复制代码
package main

import "fmt"

func main() {
    var age int
    age = 25
    fmt.Println(age)
}
bash 复制代码
25

🐒:

这种声明方式乍一看比第一个还复杂,但我用的比较多,例如初始化结构体,然后根据需求挨个进行赋值。


示例:短变量声明


go 复制代码
package main

import "fmt"

func main() {
    age := 25
    fmt.Println(age)
}
bash 复制代码
25

🐒:

这种声明方式最简洁,我用的也多,例如调用函数的时接收结果( res, _ := myFun() )。


示例:多变量声明


go 复制代码
import "fmt"

func main() {
    var (
       age  int    = 25
       name string = "windy"
    )
    fmt.Println(age, name)
    
    var a, b = 1, 2
    fmt.Println(a, b)
}
// 也可以删除类型,结果是一样的
bash 复制代码
25 windy
12

🐒:

这种声明方式我基本上就是了解了解,就没用过。


短变量声明的一些小细节

作用域限制: 只能用在函数内部,不能用于包级别
重复声明规则: 在同一代码块中,若左侧变量名至少有一个是新变量,则允许对旧变量使用 :=(此时旧变量的行为是赋值而非重新声明)。
特殊的空白标识符 : 如果函数的返回值有些不需要,可以给变量取名为下划线 _


示例:重复声明规则

运行成功

go 复制代码
package main

import "fmt"

func myFunOne() (string, error) {
	return "Hello", nil
}

func myFunTwo() (string, error) {
	return "world", nil
}

func main() {
	one, err := myFunOne() // 声明 a 和 err
	two, err := myFunTwo() // 声明 b,对 err 赋值(合法,因为 b 是新的)
	fmt.Println(one, two, err)
}
bash 复制代码
Hello world <nil>

没编译时就提示报错

go 复制代码
package main

import "fmt"

func myFunOne() (string, error) {
    return "Hello", nil
}

func myFunTwo() (string, error) {
    return "world", nil
}

func main() {
    one, err := myFunOne() // 声明 a 和 err
    one, err := myFunTwo()  // 报错,左侧无新变量
    fmt.Println(one, err)
}
// 报错提示:No new variables on the left side of ':=', Replace with'='
// 左边没有新变量,直接用 = 即可(会覆盖之前的值)

特殊的空白标识符

Go 的短变量声明 := 中,下划线 _ 是一个特殊的空白标识符。它用于占位,表示主动忽略某个返回值或声明项。关于它的使用,有几个关键点需要特别注意:

  • _ 不算"新变量",不参与重复声明规则的判定

    • := 左侧,只要出现至少一个非 _ 的新变量名,声明就是合法的。
    • _ 可以被重复使用任意多次,它不会导致编译错误,也不会被视为新的有效变量。
  • _ 无法被读取,只用于占位丢弃值

    • _ 本质上不绑定任何值。你不能试图读取或使用它。
    • 它最常见的场景是处理函数的多返回值,比如忽略 error
  • _ 声明的变量 "未使用" 不会报错

    • Go 编译器强制要求声明的非 _ 变量必须被使用。但 _ 是唯一的例外,它可以被多次 "声明" 且永不使用。
  • _ 不能用于常量或类型声明

    • _ 仅在 变量声明 和 赋值 场景作为占位符,不能用于 consttype 定义。
  • := 中左侧全是 _ 是语法错误

    • 即使你只是为了调用一个函数并忽略其所有返回值,也不能写 _ := myFun()
    • 正确做法是 直接调用使用普通赋值(非短声明)
  • 记住:_ 当成黑洞,它只为满足语法结构而存在,不参与任何变量计数的逻辑。


常量


定义

编译时确定、运行时不改变的值


声明方式

方式 语法 示例
标准声明 const 常量名 类型 = 表达式 const Age int = 25
类型推断 const 常量名 = 表达式 const Age = 25
多常量声明 const (常量1 类型1 = 值1 ...) const (Age int = 25; Name string = "windy")
隐式重复 多常量声明块中省略右值时自动沿用上一行表达式 const ( A = 1; B; C )

示例:标准声明


go 复制代码
package main

import "fmt"

func main() {
    const age int = 25
    fmt.Println(age)
}
bash 复制代码
25

🐒:

这种声明方式虽然有点麻烦,但很清晰明了。一般来说,常量定义的数量比变量少很多,且大多数都定义在函数外,调用常量的时候能一下子知道是什么类型的会比较好。


示例:类型推断


go 复制代码
package main

import "fmt"

func main() {
    const age = 25
    fmt.Println(age)
}
bash 复制代码
25

🐒:

这种声明方式个人习惯上不常使用,推荐第一种。


示例:多常量声明


go 复制代码
package main

import "fmt"

func main() {
    const (
       age  int    = 25
       name string = "windy"
    )
    fmt.Println(age, name)
}
// 也可以删除类型,结果是一样的
bash 复制代码
25 windy

🐒:

这种声明方式一般在定义差不多含义的常量的时候使用,比如返回码( 200,404,500 等 )。


示例:隐式重复


go 复制代码
package main

import "fmt"

func main() {
    const (
       Apple  = "fruit"
       Banana // = "fruit"
       Cherry // = "fruit"
    )
    // Banana 和 Cherry 的值都是 "fruit"
    fmt.Println(Apple, Banana, Cherry)
}
bash 复制代码
fruit fruit fruit

🐒:

基本上没用过这种声明方式,不知道以后会不会有用得到的场景


命名规则


标识符语法规则(强制)

  • 由字母(Unicode 字母)、数字、下划线 _ 组成。
  • 不能以数字开头
  • 区分大小写 ,例如 Namename 是不同的。
  • 不能是 Go 语言的 关键字 ,例如 funcvarconstiffor 等。
  • 下划线 _特殊的空白标识符,不能作为常规变量名使用(声明即丢弃)。

导出规则(可见性控制)

Go 没有 public/private 关键字,而是用 首字母的大小写 控制包外可见性:

首字母 可见性 术语
大写 包外可访问 Exported (导出标识符)
小写下划线 仅包内可访问 Unexported (未导出标识符)

命名风格约定(非强制,但强烈推荐)

Go 社区遵循一套统一的命名风格,保证了代码的可读性和一致性:

对象类型 风格 示例
变量 驼峰式 (camelCase) userCount, httpRequest
常量 驼峰式 (PascalCasecamelCase) MaxRetries (导出), defaultPort (未导出)
函数 / 方法 驼峰式 GetUser, parseData
类型名 驼峰式,首字母大写(导出) UserService, httpClient (未导出)
包名 全小写,简短,无下划线 time, httputil, strings
接口名 通常以 er 结尾(单方法接口) Reader, Writer, Closer
缩写词 全大写或全小写,保持一致 HTTPServer (或 httpServer),不能 写成 HttpServer

特殊命名约定 与 注意点

  • _ (空白标识符) :用于占位忽略值。
  • _test 后缀 :文件名 xxx_test.go 是测试文件,包名通常是 xxx_test 或原包名。
  • 内部包 internal :路径中包含 /internal/ 的包只能被其父目录下的包导入,是一种强制的可见性控制。
  • 避免无意义的包名 :如 utilcommonhelper,尽量使用描述功能的具体名字。

使用范围(作用域 Scope)


作用域决定了标识符( 变量名、常量名 )在代码中的可见范围。Go 的作用域是词法作用域静态作用域 ),由代码块 {} 界定。


作用域层级(从大到小)

级别 声明位置 可见范围
全局作用域 所有函数之外 整个包(package)内
包级私有 函数外,首字母小写 仅当前包
包级导出 函数外,首字母大写 当前包 + 其他导入此包的包
函数作用域 函数体内任何位置 该函数体内(从声明点到函数结束)
块作用域 ifforswitch{} 仅该花括号块内

作用域遮蔽 (Shadowing)

内层作用域声明的变量若与外层同名,会 遮蔽 外层变量 。这是 Go 代码中非常常见的


示例


go 复制代码
package main

import "fmt"

var myName = "true" // 包级变量

func main() {
    fmt.Println(myName) // 输出 true

    // 在块内声明同名变量,创建了新变量而非修改外层
    if true {
       var myName = "false"
       fmt.Println(myName)
       // 这个 myName 是块内新变量,值为 false
    }
    fmt.Println(myName) // 仍然输出 true,包级变量未被修改
}
bash 复制代码
true
false
true

🐒:

为了节省脑子,尽量不重名,如果实在不想思考其他切合的名字,就直接 name1name2


避免遮蔽的建议


  • 使用 go vet-shadow 选项检测(go vet -shadow ./...)。
  • 在内部作用域中,若意图修改外层变量,直接使用赋值 = 而非 :=

包级变量 与 常量 的初始化顺序

  • 在同一个包内,多个 .go 文件中的包级变量按 文件名字母顺序 初始化。
  • 单个文件内,按声明顺序 从上到下 初始化。
  • 若初始化表达式引用其他包级变量,Go 会处理依赖关系,禁止循环引用
  • 常量在编译时求值,不依赖运行时初始化顺序。

相关推荐
希望永不加班2 小时前
SpringBoot 缓存一致性:缓存与数据库双写策略
数据库·spring boot·后端·缓存·oracle
胖纳特2 小时前
从零到一:OnlyOffice中国版企业级完整落地指南
前端·后端
FelixBitSoul2 小时前
Go 语言面试深度全攻略:从工程化到底层原理,一文通杀
后端·go
暮年2 小时前
Java 并发锁-ReentrantLock
后端
用户537712853042 小时前
如何通过自定义注解实现零代码侵入的方法日志记录
后端
橙子不要熬夜2 小时前
构建一个会调用工具和定时任务的AI智能助手
后端
Gopher_HBo2 小时前
图解Go语言逃逸
后端
MiNG MENS2 小时前
Spring Boot + Vue 全栈开发实战指南
vue.js·spring boot·后端
2601_949816582 小时前
Spring Boot--@PathVariable、@RequestParam、@RequestBody
java·spring boot·后端