我们继续学习 Go 语言的数据类型!数据类型决定了变量可以存储什么类型的值以及可以对它们进行哪些操作。Go 是静态类型语言,每个变量都有明确的类型,这有助于提高代码的安全性和可读性。
我们将数据类型分为两大类:基本数据类型和复合数据类型。
一、基本数据类型
基本数据类型是构成程序的基础,包括数字、字符串和布尔值。
1. 整数类型
Go 提供了多种整数类型,区别在于长度和有无符号。
| 类型 | 说明 | 取值范围 |
|---|---|---|
int | 平台相关,32位系统为32位,64位系统为64位 | 有符号整数 |
int8 | 8位有符号整数 | -128 ~ 127 |
int16 | 16位有符号整数 | -32768 ~ 32767 |
int32 | 32位有符号整数 | -2147483648 ~ 2147483647 |
int64 | 64位有符号整数 | -9223372036854775808 ~ 9223372036854775807 |
uint | 平台相关,无符号整数 | 非负数 |
uint8 | 8位无符号整数 | 0 ~ 255 |
uint16 | 16位无符号整数 | 0 ~ 65535 |
uint32 | 32位无符号整数 | 0 ~ 4294967295 |
uint64 | 64位无符号整数 | 0 ~ 18446744073709551615 |
💡 提示:日常开发中,如果不关心具体位数,直接使用
int即可。当需要明确大小(如二进制协议、性能优化)时,使用指定长度的类型。
示例:
var a int = 100
var b int8 = 10
var c uint = 200
sum := a + int(b) // 不同类型需要显式转换
fmt.Println(sum)
2. 浮点数类型
Go 有两种浮点数类型:float32 和 float64(常用)。
float32:约6位十进制精度float64:约15位十进制精度
示例:
var pi float64 = 3.141592653589793
var price float32 = 19.99
fmt.Printf("pi 类型:%T,值:%f\n", pi, pi)
3. 复数类型
Go 原生支持复数:complex64(实部和虚部都是float32)和 complex128(实部和虚部都是float64)。
示例:
var c1 complex64 = 1 + 2i
c2 := 3 + 4i // 类型推断为 complex128
fmt.Println(c1, c2)
fmt.Println(real(c1), imag(c1)) // 获取实部和虚部
4. 布尔类型
bool 类型只有两个值:true 和 false。默认零值为 false。
示例:
var isOK bool = true
isReady := false
fmt.Println(isOK && isReady) // 逻辑运算
5. 字符串类型
string 是 Go 中的字符串类型,支持 Unicode,默认零值为空字符串 ""。字符串可以通过 + 连接。
示例:
var name string = "Go语言"
greet := "Hello, " + name
fmt.Println(greet)
fmt.Println(len(name)) // 字节长度
fmt.Println(name[0]) // 访问第一个字节(非字符)
⚠️ 注意:字符串是不可变的,不能通过索引修改。
6. byte 和 rune 类型
byte是uint8的别名,通常表示 ASCII 字符。rune是int32的别名,通常表示一个 Unicode 码点(即一个字符,可能占多个字节)。
示例:
var b byte = 'A' // 单引号表示字符
var r rune = '中' // Unicode 字符
fmt.Printf("byte: %c, rune: %c\n", b, r)
二、复合数据类型
复合数据类型由基本数据类型组合而成,可以表示更复杂的数据结构。
1. 数组(Array)
数组是固定长度的同类型元素序列。长度是数组类型的一部分,一旦定义不可改变。
声明方式:
var 数组名 [长度]元素类型
var 数组名 = [长度]元素类型{值1, 值2, ...}
数组名 := [...]元素类型{值1, 值2, ...} // ... 让编译器自动计算长度
示例:
var arr1 [3]int // [0 0 0]
arr2 := [3]string{"a", "b"} // ["a" "b" ""] 缺失的元素为零值
arr3 := [...]int{1, 2, 3, 4} // 长度由初始化值决定
fmt.Println(arr2[0]) // 访问元素
arr1[1] = 10 // 修改元素
fmt.Println(arr1) // [0 10 0]
数组在 Go 中是值类型,赋值或传参会复制整个数组。
2. 切片(Slice)
切片是对数组的动态视图,长度可变,是 Go 中常用的数据结构。切片本身不存储数据,只是描述底层数组的一段。
声明方式:
var s []int // nil 切片,长度0
s := []int{1, 2, 3} // 创建切片并初始化
s := make([]int, 5) // 创建长度为5的切片,元素为零值
s := make([]int, 5, 10) // 长度为5,容量为10
常用操作:
len(s)获取长度cap(s)获取容量append(s, 4, 5)追加元素,可能扩容s[low:high]切片操作,左闭右开
示例:
arr := [5]int{10, 20, 30, 40, 50}
s1 := arr[1:4] // [20 30 40]
s2 := make([]int, 3) // [0 0 0]
s2 = append(s2, 100) // [0 0 0 100]
// 遍历切片
for i, v := range s1 {
fmt.Printf("索引 %d: 值 %d\n", i, v)
}
💡 切片是引用类型,多个切片可能共享底层数组,修改会影响其他切片。
3. 映射(Map)
Map 是无序的键值对集合,键必须是可比较的类型(如基本类型、指针、数组、结构体等),值可以是任意类型。
声明方式:
var m map[string]int // nil 映射,不能直接赋值
m = make(map[string]int) // 初始化
m := map[string]int{"age": 18, "score": 100}
常用操作:
m[key] = value插入或修改value, ok := m[key]获取值,ok表示键是否存在delete(m, key)删除键值对len(m)获取元素个数
示例:
scores := map[string]int{
"小明": 90,
"小红": 85,
}
scores["小刚"] = 95 // 新增
delete(scores, "小红") // 删除
if score, ok := scores["小明"]; ok {
fmt.Println("小明的分数:", score)
}
4. 结构体(Struct)
结构体是将零个或多个任意类型的变量组合在一起的复合类型,类似于其他语言中的“类”,但只有字段,没有方法(方法可以单独定义)。
定义与使用:
type Person struct {
Name string
Age int
}
func main() {
// 初始化方式
var p1 Person // 字段为零值
p2 := Person{"张三", 30} // 顺序必须一致
p3 := Person{Name: "李四", Age: 25} // 推荐,指定字段名
p4 := new(Person) // 返回指针,字段为零值
// 访问和修改字段
p1.Name = "王五"
p1.Age = 28
fmt.Println(p1.Name, p1.Age)
}
结构体是值类型,赋值或传参会复制整个结构体。如果希望共享,可以使用指针。
5. 其他复合类型简介
- 指针(Pointer):
*T表示指向类型 T 的指针。用于间接访问变量值。 - 函数(Function):函数也是一种类型,可以赋值给变量、作为参数或返回值。
- 接口(Interface):定义一组方法签名,实现多态。
- 通道(Channel):用于 goroutine 之间的通信。
这些属于进阶内容,待你熟悉基础后再深入学习。
三、类型转换
Go 不支持隐式类型转换,不同类型之间必须显式转换。
语法:T(v) 将值 v 转换为类型 T
示例:
var i int = 42
var f float64 = float64(i) // int 转 float64
var u uint = uint(f) // float64 转 uint
⚠️ 转换时要注意精度丢失或溢出。
四、零值
在 Go 中,任何变量在声明后如果没有显式初始化,都会被赋予对应类型的零值。零值是类型默认值,不会出现未定义行为。
| 类型 | 零值 |
|---|---|
| 数值类型(int, float等) | 0 |
| 布尔类型 | false |
| 字符串 | ""(空字符串) |
| 指针、切片、映射、通道、函数、接口 | nil |
| 数组 | 每个元素为其类型的零值 |
| 结构体 | 每个字段为其类型的零值 |
总结
- 基本数据类型:整数、浮点数、复数、布尔、字符串、byte/rune,是构建程序的基础砖块。
- 复合数据类型:数组(固定长度)、切片(动态长度)、映射(键值对)、结构体(字段集合),用于组织和操作更复杂的数据。
- 每种类型都有其特性和用途,选择正确的类型能让代码更清晰、高效。
- 记住零值的概念,避免未初始化变量的困扰。