1.2.1 变量声明与初始化
Go 语言提供了多种变量声明方式,灵活且类型安全。
使用 var 关键字声明
var 是 Go 中最基本的变量声明方式,适用于包级别和函数级别。
// 声明单个变量(指定类型)
var name string
var age int
// 声明并初始化
var city string = "Beijing"
var count int = 42
// 类型推断(省略类型)
var message = "Hello, Go!"
var pi = 3.14159
短变量声明 :=
短变量声明是 Go 中最常用的声明方式,只能在函数内部使用。
func main() {
// 短变量声明,自动推断类型
name := "Go语言"
version := 1.21
isStable := true
// 重新赋值(已声明的变量不能再次使用 :=)
name = "Golang"
}
注意:
:=不能用于包级别(函数外部),且左侧必须至少有一个新变量。
多变量声明
Go 支持一次声明多个变量,提高代码可读性。
// 多变量同时声明
var x, y, z int
// 多变量声明并初始化(类型可不同)
var (
username string = "admin"
port int = 8080
debug bool = false
)
// 短变量声明多个变量
a, b, c := 1, "hello", true
| 声明方式 | 语法 | 适用场景 |
|---|---|---|
var x int |
显式类型,无初始值 | 需要零值初始化、包级变量 |
var x = value |
类型推断 | 初始值类型明确、包级变量 |
x := value |
短变量声明 | 函数内部,最常用方式 |
var (...) |
批量声明 | 多个相关变量的集中声明 |
1.2.2 常量与 iota 枚举
常量声明
常量使用 const 关键字声明,值在编译期确定,不可修改。
// 单个常量
const Pi = 3.14159265358979
const AppName string = "MyApp"
// 批量声明
const (
StatusOK = 200
StatusNotFound = 404
StatusError = 500
)
iota 枚举器
iota 是 Go 的常量计数器,在 const 块中从 0 开始自增,是实现枚举的惯用方式。
// 基本用法:从 0 开始自增
const (
Sunday = iota // 0
Monday // 1
Tuesday // 2
Wednesday // 3
Thursday // 4
Friday // 5
Saturday // 6
)
iota 高级用法
// 跳过某个值
const (
_ = iota // 跳过 0
KB = 1 << (10 * iota) // 1 << 10 = 1024
MB // 1 << 20
GB // 1 << 30
TB // 1 << 40
)
// 自定义表达式
const (
FlagRead = 1 << iota // 1
FlagWrite // 2
FlagExecute // 4
)
⭐ iota 规则总结:
- 每个
const块中iota从 0 开始- 每新增一行常量声明,
iota自增 1- 同一行多个
iota值相同- 不同
const块的iota互相独立
1.2.3 基本数据类型
Go 是强类型语言,提供了丰富的内置数据类型。
整型
| 类型 | 大小 | 范围 | 说明 |
|---|---|---|---|
int8 |
1 字节 | -128 ~ 127 | 有符号 8 位整数 |
int16 |
2 字节 | -32768 ~ 32767 | 有符号 16 位整数 |
int32 |
4 字节 | -2^31 ~ 2^31-1 | 有符号 32 位整数 |
int64 |
8 字节 | -2^63 ~ 2^63-1 | 有符号 64 位整数 |
uint8 |
1 字节 | 0 ~ 255 | 无符号 8 位(即 byte) |
uint16 |
2 字节 | 0 ~ 65535 | 无符号 16 位整数 |
uint32 |
4 字节 | 0 ~ 2^32-1 | 无符号 32 位整数 |
uint64 |
8 字节 | 0 ~ 2^64-1 | 无符号 64 位整数 |
int |
平台相关 | 32 或 64 位 | 最常用,随平台变化 |
uint |
平台相关 | 32 或 64 位 | 无符号,随平台变化 |
uintptr |
平台相关 | 足以存放指针 | 用于底层编程 |
var (
a int = 42
b int64 = 9223372036854775807
c uint8 = 255
d byte = 'A' // byte 是 uint8 的别名
e rune = '中' // rune 是 int32 的别名,表示 Unicode 码点
)
浮点型
| 类型 | 大小 | 精度 |
|---|---|---|
float32 |
4 字节 | 约 6-7 位有效数字(IEEE 754 单精度) |
float64 |
8 字节 | 约 15-16 位有效数字(IEEE 754 双精度,推荐使用) |
var (
f1 float32 = 3.14
f2 float64 = 3.141592653589793
f3 = 2.718 // 默认推断为 float64
)
// 复数类型
var (
c1 complex64 = 1 + 2i
c2 complex128 = complex(3.0, 4.0)
)
布尔型
布尔类型只有 true 和 false 两个值,不能与整型互相转换。
var (
isActive bool = true
isDone bool = false
flag = true // 类型推断
)
// 布尔运算
result := (10 > 5) && (3 != 4) // true
💡 Go 与其他语言的区别: Go 中布尔值不能隐式转换为 0/1,
if 1 { }这种写法是非法的。
字符串
Go 中字符串是不可变的 UTF-8 编码字节序列。
var (
s1 string = "Hello, 世界"
s2 = "Go is awesome"
s3 = `这是原始字符串字面量
支持多行
不处理转义符 \n`
)
// 字符串操作
length := len(s1) // 字节长度
runeLen := utf8.RuneCountInString(s1) // 字符数量
concat := s1 + " " + s2 // 字符串拼接
sub := s1[0:5] // 切片(按字节)
| 常用字符串操作 | 说明 |
|---|---|
strings.Contains(s, sub) |
判断是否包含子串 |
strings.Split(s, sep) |
按分隔符切割 |
strings.Join(slice, sep) |
连接字符串切片 |
strings.Replace(s, old, new, n) |
替换子串 |
fmt.Sprintf(format, args...) |
格式化拼接 |
strconv.Itoa(n) / strconv.Atoi(s) |
整数与字符串互转 |
1.2.4 类型转换与类型推断
显式类型转换
Go 不支持隐式类型转换,所有类型转换必须显式进行。
// 语法:T(expression)
var i int = 42
var f float64 = float64(i) // int → float64
var u uint = uint(f) // float64 → uint
// 字符串与数字转换
import "strconv"
s := strconv.Itoa(42) // int → string: "42"
n, err := strconv.Atoi("42") // string → int: 42
// 字符串与字节切片互转
bytes := []byte("hello") // string → []byte
str := string(bytes) // []byte → string
🔔 类型转换的安全注意事项:
- 大范围转小范围可能溢出(如
int64→int8)- 浮点转整数会截断小数部分(非四舍五入)
- 字符串转
[]byte会拷贝数据
类型推断
Go 编译器能根据右侧的值自动推断变量类型。
// 编译器自动推断类型
i := 42 // int
f := 3.14 // float64
s := "hello" // string
b := true // bool
c := 3 + 4i // complex128
// 函数返回值推断
result := someFunction() // 类型由函数签名决定
推断规则如下:
| 字面量形式 | 推断类型 | 示例 |
|---|---|---|
| 整数字面量 | int |
x := 100 |
| 浮点数字面量 | float64 |
x := 3.14 |
| 复数字面量 | complex128 |
x := 1 + 2i |
| 字符串字面量 | string |
x := "hi" |
| 布尔字面量 | bool |
x := true |
| 字符字面量(rune) | rune(即 int32) |
x := 'A' |
1.2.5 零值(Zero Value)机制
Go 中所有变量在声明时如果没有显式赋值,会被自动初始化为该类型的零值。这一机制消除了未初始化变量的安全隐患。
var (
i int // 0
f float64 // 0.0
b bool // false
s string // ""(空字符串)
p *int // nil
sl []int // nil
m map[string]int // nil
ch chan int // nil
fn func() // nil
iface error // nil
)
各类型零值速查
| 类型 | 零值 | 备注 |
|---|---|---|
整型(int, int8 等) |
0 |
所有整型统一为 0 |
浮点型(float32, float64) |
0.0 |
|
布尔型(bool) |
false |
|
字符串(string) |
""(空字符串) |
长度为 0,非 nil |
指针(*T) |
nil |
|
切片([]T) |
nil |
nil 切片可安全 append |
映射(map[K]V) |
nil |
nil map 读取安全,写入 panic |
通道(chan T) |
nil |
nil channel 永久阻塞 |
接口(interface) |
nil |
|
函数(func) |
nil |
|
结构体(struct) |
各字段的零值 | 递归应用零值规则 |
数组([N]T) |
各元素的零值 | 长度固定,每个元素为零值 |
零值的实际应用
// 零值可直接使用的设计模式
var buf bytes.Buffer // 无需 make,零值即可用
buf.WriteString("hello")
var mu sync.Mutex // 零值即为未锁定状态
mu.Lock()
defer mu.Unlock()
// 利用零值判断是否已初始化
type Config struct {
Host string
Port int
}
var cfg Config
if cfg.Host == "" { // 利用零值判断
cfg.Host = "localhost"
}
if cfg.Port == 0 {
cfg.Port = 8080
}
⭐ 零值设计哲学: Go 的零值机制体现了 "make the zero value useful"(让零值有用)的设计理念。许多标准库类型(如
bytes.Buffer、sync.Mutex、sync.WaitGroup)都被设计为零值即可使用,无需额外初始化。
小结
核心要点:
var用于包级和函数级声明,:=仅限函数内部const+iota是 Go 实现枚举的惯用方式- Go 是强类型语言,不允许隐式类型转换
- 零值机制保证变量始终有确定的初始状态
最佳实践:
- 优先使用
:=进行局部变量声明 - 使用
var块集中管理相关变量 - 类型转换时注意溢出和精度丢失
- 善用零值设计,减少不必要的初始化代码