Go语言类型系统入门:变量、常量、数据类型一次讲透
作者:大黄说说
还在为Go的类型系统头疼吗?本文用最直白的方式讲透变量声明(var与:=)、常量(const与iota)以及四大数据类型,你将明白为什么Go写起来像动态语言,彻底搞清数组与切片的区别,避开新手最容易犯的5个错误,让Go类型系统成为你写出安全代码的基石
Go 是静态类型语言,但写起来又像动态语言那样简洁。核心原因在于它的类型推断和短声明机制。
这篇文章把三个基础概念一次讲透。
一、变量:声明、赋值与作用域
1. 标准声明
var name string = "Go" var age int = 17
var 关键字 + 变量名 + 类型 + 初始值。类型写在变量名后面,这是 Go 和 C/Java 的区别。
2. 类型推断(推荐写法)
var name = "Go" // 编译器自动推断为 string var age = 17 // 编译器自动推断为 int
类型不写,编译器根据右侧值自动确定。日常开发中这是最常用的形式。
3. 短声明:=(函数内部专用)
name := "Go" age := 17
等价于 var name = "Go",但只能在函数内部使用,不能在包级别使用。
这是新手最容易踩的坑:在 func main() 外面写 x := 1 会直接报错。
4. 多变量声明
var a, b, c int // 三个都是 int var x, y = 1, "hello" // 类型各自推断 a, b = b, a // 交换值,不需要临时变量
5. 零值
未显式初始化的变量会被赋零值:
| 类型 | 零值 |
|---|---|
| int, float | 0 |
| string | ""(空串) |
| bool | false |
| 指针、slice、map、chan、func | nil |
这意味着不存在"未初始化变量"的问题,但也意味着 var s string 得到的是 "" 而不是 nil,这和其他引用类型不同。
二、常量:const的三种用法
const Pi = 3.14159
const (
StatusOK = 200
StatusNotFound = 404
)
const (
_ = iota // 忽略,从 0 开始
KB = 1 << (10 * iota) // 1
MB = 1 << (10 * iota) // 1024
GB = 1 << (10 * iota) // 1048576
)关键点:
const只能用于编译期可确定的值(数字、字符串、布尔)const声明的变量不占用运行时内存,编译器会直接内联替换iota是常量计数器,每个const块从 0 开始,每行自动 +1
Go 没有 #define 宏,const + iota 就是替代方案。
三、数据类型:四大类 + 底层类型
1. 基础类型
| 类别 | 类型 | 说明 |
|---|---|---|
| 布尔 | bool | 只有 true / false |
| 整数 | int8 int16 int32 int64 int uint uintptr | int 的位数随平台变(32位系统=32,64位=64) |
| 浮点 | float32 float64 | float64 是默认浮点类型 |
| 复数 | complex64 complex128 | 日常很少用 |
| 字符串 | string | 不可变字节序列,底层是 []byte |
| 字符 | rune (= int32) | 表示一个 Unicode 码点,不是 byte |
| 字节 | byte (= uint8) | uint8 的别名 |
string 不可变 ≠ []byte 不可变。[]byte 可以修改,string 不行。需要修改时转成 []byte,改完再转回 string。
2. 复合类型
| 类型 | 说明 | 零值 |
|---|---|---|
| 数组 [n]T | 长度固定,值类型 | 各元素的零值 |
| 切片 []T | 长度可变,引用类型 | nil |
| map map[K]V | 键值对,引用类型 | nil |
| 结构体 struct | 自定义字段组合 | 各字段零值 |
| 指针 *T | 存储地址 | nil |
| 函数 func | 可赋值、可作为参数 | nil |
| 接口 interface | 方法集合的抽象 | nil |
| 通道 chan T | goroutine 间通信 | nil |
数组 vs 切片 是新手最大的混淆点:
var arr [3]int // 数组,长度是类型的一部分 var slice []int // 切片,长度可变 slice = arr[0:2] // 从数组切出一个切片(不拷贝数据)
数组是值类型(赋值会拷贝整个数组),切片是引用类型(赋值只拷贝头信息,底层数据共享)。
3. 底层类型与别名
type MyInt int // 定义新类型,和 int 不同(不能直接比较) type IntAlias = int // 类型别名,和 int 完全等价
type NewType OldType→ 新类型,需要显式转换type Alias = OldType→ 别名,完全等价,无需转换
这个区别在方法绑定和类型断言时非常关键。
四、一张图总结优先级
常量 const → 编译期确定,零内存,可 iota ↓ 变量 var / := → 运行时可变,有零值,有作用域 ↓ 类型系统 → 基础类型 + 复合类型 + 自定义类型 ↓ 关键设计哲学 → 零值安全 + 类型推断 + 值/引用语义清晰
五、最容易犯的 5 个错误
| 错误 | 正确做法 |
|---|---|
| 包级别用 := | 包级别只能用 var |
| var s string 期待 nil | string 零值是 "",不是 nil |
| 以为数组和切片一样 | 数组是值类型,切片是引用类型 |
| const 里放函数调用 | const 只能放编译期常量 |
| int 跨平台不一致 | 需要固定位数时用 int32 / int64 |
把这三块吃透,Go 的类型系统就不再是障碍,而是你写出安全代码的基础设施。
六、总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
