Go 是一门静态强类型语言,变量必须先声明(或定义)才能使用,而且类型一旦确定不可改变。
1单变量声明的 3 种方式
1.1标准形式(var关键字+显式类型)
语法:var 变量名称 类型 = 表达式
var name string = "Tom"
var age int = 18
var isMarried bool = false
- 可以写在函数内外(函数外就是包级变量)
- 不赋值时自动获得零值(下面会详细讲)
1.2类型推断(var+自动推断)
语法:var 变量名称 = 表达式
编译器根据初始值自动推断类型,写法更简洁:
var name = "Tom" // 推断为 string
var age = 18 // 推断为 int
var height = 1.88 // 推断为 float64
var isMarried = true // 推断为 bool
1.3简短声明(:=)——最常用!
只能在函数内部使用,Go 独有的语法糖:
func main() {
name := "Tom" // 自动推断为 string
age := 28 // 自动推断为 int
score := 99.5 // 自动推断为 float64
}
重要规则:
:=左侧至少要有一个新变量- 同一个作用域内不能对已存在的变量再次使用
:=
错误示例:
func main() {
x := 100
// x := 200 // 编译错误!no new variables on left side of :=
x = 200 // 正确,这是赋值,不是重新声明
}
正确示例(至少有一个新变量):
func main() {
x := 100
x, y := 200, "abc" // x 是已存在变量,y 是新变量 → 合法
fmt.Println(x, y) // 200 abc
}
2多变量声明的 4 种方式
2.1一次声明多个变量(同类型)
var a, b, c int
var name1, name2, name3 string = "张三", "李四", "王五"
2.2一次声明多个变量(不同类型)
var name, age, isStudent = "Lucy", 20, true
2.3并行赋值(最常见)
var width, height = 100, 200
width, height = 300, 400 // 同时赋值
width, height = height, width // 不用临时变量就能交换
2.4变量组声明(推荐用于包级变量,当然函数内也能使用)
var (
appName string = "GoWeb"
version string = "1.0.0"
debug bool = true
maxRetry int = 5
pi float64 = 3.14159
)
3Go的零值(默认值)机制
在Go语⾔中,每种类型都有相应的默认值,我们将其称为零值(zero value)。 Go不会出现“未初始化变量”这种运行时错误,所有变量声明后都会自动获得对应类型的零值:
| 类型 | 零值 |
|---|---|
| int / float | 0 |
| bool | false |
| string | ""(空字符串) |
| pointer | nil |
| slice/map/chan | nil |
| struct | 所有字段都是零值 |
var a int
var b string
var c bool
var d *int
fmt.Printf("%d %q %t %v\n", a, b, c, d) // 0 "" false <nil>
4匿名变量“_”
在多返回值函数中经常只关心部分返回值,用 _ 丢弃不需要的值:
func getUser() (string, int, bool) {
return "Tom", 18, true
}
func main() {
name, _, isVip := getUser() // 只关心名字和是否VIP
_, age, _ := getUser() // 只关心年龄
fmt.Println(name, age, isVip)
}
遍历时同理:
for _, item := range list {
}
Python 程序员会感觉非常亲切,和
for _, item in enumerate(arr)完全一样!
5变量命名规范与注意事项(必背)
| 规则 | 示例 | 说明 |
|---|---|---|
| 只能包含字母、数字、下划线 | user_name, age2 | |
| 必须以字母或下划线开头 | _temp, Name | 不能以数字开头 |
| 区分大小写 | age ≠ Age | |
| 不能是关键字 | var, func, package 等 | Go 一共 25 个关键字 |
| 建议使用驼峰命名法 | userName, maxRetryCount | 不要用下划线 |
| 见名知意,越短越好 | i, j, k(循环索引) | 短变量只在小作用域使用 |
| 首字母大写即为导出 | AppVersion | 小写则包外不可见 |
6常见编译错误及解决办法
// 错误1:变量声明了没使用
var temp int // 编译报错:temp declared and not used
// 错误2:重复使用 := 声明已存在变量
x := 10
x := 20 // 编译错误:no new variables on left side of :=
// 错误3:函数外使用 :=
package main
name := "global" // 编译错误!只能在函数内部使用
7变量完整示例代码
package main
import "fmt"
// 包级变量(推荐使用 var() 方式)
var (
AppName = "GoStudy"
Version = "1.0.0"
DebugMode = true
)
func main() {
// 1. 标准声明
var name string = "Tom"
var age int = 28
// 2. 类型推断
var city = "Beijing"
// 3. 简短声明(最常用)
score := 99.5
isLogin := true
// 4. 多变量声明
x, y, z := 10, 20, 30
// 5. 匿名变量
username, _, vip := getUserInfo()
fmt.Printf("欢迎来到 %s v%s\n", AppName, Version)
fmt.Println(name, age, city, score, isLogin)
fmt.Println(x, y, z)
fmt.Println("用户:", username, "VIP:", vip)
}
func getUserInfo() (string, int, bool) {
return "Jerry", 35, true
}
运行结果:
欢迎来到 GoStudy v1.0.0
Tom 28 Beijing 99.5 true
10 20 30
用户: Jerry VIP: true
8变量小结(背会这5点就够了)
- 函数内最常用
变量名 := 值 - 函数外只能用
var(推荐用var()批量声明) - 声明了必须使用,否则编译不通过
- 同一个作用域内,
:=左侧至少有一个新变量 - 不关心的返回值用
_丢弃
9常量声明
常量用 const 声明,值在编译期确定,运行期间不能修改。
const LENGTH int = 10 // 显式类型
const b = "abc" // 隐式类型,自动推断
const a, c, d = 1, false, "str" // 多重赋值
常量的类型只能是布尔型、数字型(整数/浮点/复数)、字符串型,数组、切片、map、struct、函数都不行。
10常量组
const (
appName string = "GoWeb"
version = "1.0.0"
maxRetry int = 5
)
10.1省略类型和值 → 与上一行完全相同
const (
x int = 16
y // 16,int
s = "abc"
z // "abc",string
)
y、z 既没写类型也没写值,直接继承上一行的类型和值。
10.2常量组内不能重名
const (
unknown = 0
male = 1
female = 2
male = 3 // 编译错误:'male' redeclared in this block
)
10.3常量必须赋值
const j string 不能通过编译,常量没有“只声明不赋值”这种写法。
11iota
iota 是常量计数器,只能用在 const 块里:每个 const 块开始时归零,每换一行加 1。
const (
a = iota // 0
b // 1
c // 2
)
b、c 没写 = iota,但继承了上一行的表达式,等价于 b = iota、c = iota。
11.1每个 const 关键字都是新的一轮
const a = iota // 0
const (
b = iota // 0 ← 重新从 0 开始
c // 1
)
11.2中断后不会自动恢复
const (
a = iota // 0
b // 1
c // 2
d = "ha" // "ha" iota = 3
e // "ha" iota = 4
f = 100 // 100 iota = 5
g // 100 iota = 6
h, i = iota, iota // 7, 7
j = iota // 8
)
d、e 的值是 "ha",f、g 的值是 100,但行号一直在走,iota 并没有停。想恢复计数,必须显式写 = iota(比如 j)。
11.3iota 可以参与运算
const (
A1 = (iota + 1) * 100 // 100
B1 // 200
C1 // 300
D1 = 10 // 10
E1 = "hello" // hello
F1 // hello
G1 = iota // 6
)
11.4用 iota 做枚举
Go 没有 enum,用常量组 + iota 代替:
const (
Unknown = iota // 0
Female // 1
Male // 2
)
12常量与变量的区别
| 变量 | 常量 | |
|---|---|---|
| 声明方式 | var x int / x := 1 | const x = 1 |
| 能否修改 | 能 | 不能 |
| 声明后未使用 | 编译报错 | 不报错 |
| 声明不赋值 | 可以,取零值 | 不可以 |
| 值何时确定 | 运行时 | 编译期 |
另外几点:
- 常量不能取地址——数字常量不分配存储空间,没有内存地址
- 常量的值必须在编译期就能算出来,
const t = time.Now()编译不过 - 同一常量组内名字不能重复
13常量小结
- 常量用
const声明,值不可修改,类型只能是布尔、数字、字符串 - 常量组中某一行省略类型和值,就继承上一行
iota在每个 const 块里从 0 开始,每行加 1,中断后要显式写= iota才能恢复- Go 没有枚举类型,用常量组 +
iota模拟 - 常量声明了不用不会报错,变量会