Go 数据类型详解
数组(Array)
数组的特点
- 固定长度
- 元素类型相同
- 内存连续存储
- 值类型(传递时会复制)
数组声明和初始化
// 声明数组
var arr1 [5]int // 零值数组
var arr2 = [5]int{1, 2, 3, 4, 5} // 完整初始化
var arr3 = [...]int{1, 2, 3} // 自动推断长度
var arr4 = [5]int{1, 2} // 部分初始化,其余为零值
// 指定索引初始化
var arr5 = [5]int{0: 10, 2: 20, 4: 40} // [10, 0, 20, 0, 40]
数组操作
package main
import "fmt"
func main() {
arr := [5]int{1, 2, 3, 4, 5}
// 访问元素
fmt.Println(arr[0]) // 1
fmt.Println(arr[4]) // 5
// 修改元素
arr[0] = 10
fmt.Println(arr) // [10, 2, 3, 4, 5]
// 数组长度
fmt.Println(len(arr)) // 5
// 遍历数组
for i := 0; i < len(arr); i++ {
fmt.Printf("arr[%d] = %d\n", i, arr[i])
}
// 使用range遍历
for index, value := range arr {
fmt.Printf("索引: %d, 值: %d\n", index, value)
}
}
多维数组
// 二维数组
var matrix [3][4]int
// 初始化二维数组
var matrix2 = [3][4]int{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
}
// 访问二维数组
matrix2[0][0] = 100
fmt.Println(matrix2[0][0]) // 100
// 遍历二维数组
for i := 0; i < len(matrix2); i++ {
for j := 0; j < len(matrix2[i]); j++ {
fmt.Printf("%d ", matrix2[i][j])
}
fmt.Println()
}
切片(Slice)
切片的特点
- 动态长度
- 引用类型
- 基于数组实现
- 包含指针、长度、容量
切片创建
// 方式1:从数组创建
arr := [5]int{1, 2, 3, 4, 5}
slice1 := arr[1:4] // [2, 3, 4]
slice2 := arr[:3] // [1, 2, 3]
slice3 := arr[2:] // [3, 4, 5]
slice4 := arr[:] // [1, 2, 3, 4, 5]
// 方式2:直接声明
var slice5 []int // nil切片
slice6 := []int{1, 2, 3, 4, 5} // 字面量
// 方式3:使用make
slice7 := make([]int, 5) // 长度为5,容量为5
slice8 := make([]int, 5, 10) // 长度为5,容量为10
切片操作
package main
import "fmt"
func main() {
slice := []int{1, 2, 3}
// 添加元素
slice = append(slice, 4) // [1, 2, 3, 4]
slice = append(slice, 5, 6, 7) // [1, 2, 3, 4, 5, 6, 7]
// 添加另一个切片
other := []int{8, 9, 10}
slice = append(slice, other...) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 长度和容量
fmt.Printf("长度: %d, 容量: %d\n", len(slice), cap(slice))
// 切片操作
subSlice := slice[2:5] // [3, 4, 5]
fmt.Println(subSlice)
// 复制切片
newSlice := make([]int, len(slice))
copy(newSlice, slice)
// 删除元素(删除索引为2的元素)
index := 2
slice = append(slice[:index], slice[index+1:]...)
}
切片的内存模型
package main
import "fmt"
func main() {
// 切片的底层数组
arr := [5]int{1, 2, 3, 4, 5}
slice1 := arr[1:4] // [2, 3, 4]
slice2 := arr[2:5] // [3, 4, 5]
// 修改slice1会影响底层数组和slice2
slice1[1] = 100 // 修改arr[2]
fmt.Println(arr) // [1, 2, 100, 4, 5]
fmt.Println(slice2) // [100, 4, 5]
// 切片扩容
slice3 := []int{1, 2, 3}
fmt.Printf("扩容前 - 长度: %d, 容量: %d\n", len(slice3), cap(slice3))
slice3 = append(slice3, 4, 5, 6, 7)
fmt.Printf("扩容后 - 长度: %d, 容量: %d\n", len(slice3), cap(slice3))
}
映射(Map)
映射的特点
- 键值对存储
- 引用类型
- 无序
- 键必须是可比较类型
映射创建和初始化
// 方式1:使用make
var m1 map[string]int
m1 = make(map[string]int)
// 方式2:直接初始化
m2 := map[string]int{
"apple": 5,
"banana": 3,
"orange": 8,
}
// 方式3:make with capacity
m3 := make(map[string]int, 10)
映射操作
package main
import "fmt"
func main() {
// 创建映射
scores := map[string]int{
"Alice": 95,
"Bob": 87,
"Charlie": 92,
}
// 添加/修改元素
scores["David"] = 88
scores["Alice"] = 98 // 修改已存在的键
// 获取元素
aliceScore := scores["Alice"]
fmt.Printf("Alice的分数: %d\n", aliceScore)
// 检查键是否存在
score, exists := scores["Eve"]
if exists {
fmt.Printf("Eve的分数: %d\n", score)
} else {
fmt.Println("Eve不在记录中")
}
// 删除元素
delete(scores, "Bob")
// 遍历映射
for name, score := range scores {
fmt.Printf("%s: %d\n", name, score)
}
// 映射长度
fmt.Printf("总人数: %d\n", len(scores))
}
复杂映射
// 嵌套映射
studentGrades := map[string]map[string]int{
"Alice": {
"Math": 95,
"English": 87,
"Science": 92,
},
"Bob": {
"Math": 78,
"English": 85,
"Science": 88,
},
}
// 访问嵌套映射
mathScore := studentGrades["Alice"]["Math"]
fmt.Printf("Alice的数学成绩: %d\n", mathScore)
// 切片作为映射的值
groups := map[string][]string{
"frontend": {"Alice", "Bob"},
"backend": {"Charlie", "David"},
"devops": {"Eve"},
}
结构体(Struct)
结构体定义
// 定义结构体
type Person struct {
Name string
Age int
Email string
Address string
}
// 嵌套结构体
type Address struct {
Street string
City string
Province string
ZipCode string
}
type Employee struct {
Person // 匿名字段(嵌入)
ID int
Position string
Salary float64
Address Address // 命名字段
}
结构体初始化
package main
import "fmt"
type Person struct {
Name string
Age int
City string
}
func main() {
// 方式1:字段名初始化
p1 := Person{
Name: "张三",
Age: 25,
City: "北京",
}
// 方式2:按顺序初始化
p2 := Person{"李四", 30, "上海"}
// 方式3:部分初始化
p3 := Person{
Name: "王五",
Age: 28,
// City使用零值
}
// 方式4:使用new
p4 := new(Person)
p4.Name = "赵六"
p4.Age = 35
p4.City = "广州"
fmt.Println(p1, p2, p3, *p4)
}
结构体操作
package main
import "fmt"
type Student struct {
Name string
Age int
Grades map[string]int
}
func main() {
// 创建学生
student := Student{
Name: "小明",
Age: 18,
Grades: map[string]int{
"Math": 95,
"English": 87,
"Science": 92,
},
}
// 访问字段
fmt.Printf("姓名: %s\n", student.Name)
fmt.Printf("年龄: %d\n", student.Age)
// 修改字段
student.Age = 19
student.Grades["Math"] = 98
// 结构体指针
studentPtr := &student
fmt.Printf("姓名: %s\n", studentPtr.Name) // 自动解引用
fmt.Printf("年龄: %d\n", (*studentPtr).Age)
// 结构体比较
student1 := Student{Name: "Alice", Age: 20}
student2 := Student{Name: "Alice", Age: 20}
fmt.Println(student1 == student2) // true(如果所有字段都可比较)
}
匿名结构体
// 匿名结构体
person := struct {
Name string
Age int
}{
Name: "匿名",
Age: 25,
}
fmt.Printf("%+v\n", person)
接口(Interface)
接口定义
// 定义接口
type Writer interface {
Write([]byte) (int, error)
}
type Reader interface {
Read([]byte) (int, error)
}
// 组合接口
type ReadWriter interface {
Reader
Writer
}
// 空接口
type Any interface{} // 或者 interface{}
接口实现
package main
import "fmt"
// 定义接口
type Shape interface {
Area() float64
Perimeter() float64
}
// 矩形结构体
type Rectangle struct {
Width, Height float64
}
// 实现Shape接口
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
// 圆形结构体
type Circle struct {
Radius float64
}
// 实现Shape接口
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * 3.14159 * c.Radius
}
// 使用接口的函数
func printShapeInfo(s Shape) {
fmt.Printf("面积: %.2f, 周长: %.2f\n", s.Area(), s.Perimeter())
}
func main() {
rect := Rectangle{Width: 5, Height: 3}
circle := Circle{Radius: 4}
printShapeInfo(rect)
printShapeInfo(circle)
// 接口切片
shapes := []Shape{rect, circle}
for _, shape := range shapes {
printShapeInfo(shape)
}
}
类型断言和类型选择
package main
import "fmt"
func main() {
var i interface{} = "Hello"
// 类型断言
s := i.(string)
fmt.Println(s)
// 安全的类型断言
s, ok := i.(string)
if ok {
fmt.Printf("字符串: %s\n", s)
}
// 类型选择
switch v := i.(type) {
case string:
fmt.Printf("字符串: %s, 长度: %d\n", v, len(v))
case int:
fmt.Printf("整数: %d\n", v)
case bool:
fmt.Printf("布尔值: %t\n", v)
default:
fmt.Printf("未知类型: %T\n", v)
}
}
指针(Pointer)
指针基础
package main
import "fmt"
func main() {
var x int = 42
var p *int = &x // p是指向x的指针
fmt.Printf("x的值: %d\n", x)
fmt.Printf("x的地址: %p\n", &x)
fmt.Printf("p的值: %p\n", p)
fmt.Printf("p指向的值: %d\n", *p)
// 通过指针修改值
*p = 100
fmt.Printf("修改后x的值: %d\n", x)
// 指针的零值
var p2 *int
fmt.Printf("p2的值: %v\n", p2) // <nil>
// 使用new创建指针
p3 := new(int)
*p3 = 200
fmt.Printf("p3指向的值: %d\n", *p3)
}
指针与函数
package main
import "fmt"
// 值传递
func modifyValue(x int) {
x = 100
}
// 指针传递
func modifyPointer(x *int) {
*x = 100
}
// 结构体指针
type Person struct {
Name string
Age int
}
func modifyPerson(p *Person) {
p.Name = "Modified"
p.Age = 100
}
func main() {
// 基本类型指针
x := 42
fmt.Printf("修改前: %d\n", x)
modifyValue(x)
fmt.Printf("值传递后: %d\n", x) // 42,未改变
modifyPointer(&x)
fmt.Printf("指针传递后: %d\n", x) // 100,已改变
// 结构体指针
person := Person{Name: "Alice", Age: 25}
fmt.Printf("修改前: %+v\n", person)
modifyPerson(&person)
fmt.Printf("修改后: %+v\n", person)
}
类型别名和类型定义
类型别名
// 类型别名
type MyInt = int
type MyString = string
var x MyInt = 42 // x的类型实际上是int
var s MyString = "hello" // s的类型实际上是string
类型定义
// 新类型定义
type UserID int
type UserName string
// 为新类型定义方法
func (id UserID) String() string {
return fmt.Sprintf("User-%d", int(id))
}
func main() {
var id UserID = 123
var name UserName = "Alice"
fmt.Println(id.String()) // User-123
// 需要显式转换
var normalInt int = int(id)
var normalString string = string(name)
}
总结
本课我们深入学习了Go语言的数据类型:
- 数组:固定长度,值类型
- 切片:动态长度,引用类型,基于数组
- 映射:键值对存储,引用类型
- 结构体:自定义类型,组合数据
- 接口:定义行为,实现多态
- 指针:内存地址,引用传递
下一课预告
在下一课中,我们将学习Go语言的函数和方法,包括:
- 函数的高级特性
- 方法的定义和使用
- 接口的深入应用
- 错误处理机制
💡 小贴士:理解值类型和引用类型的区别是掌握Go语言的关键,多练习指针和接口的使用。
📚 文章对你有帮助?请关注我的公众号,万分感谢!
获取更多优质技术文章,第一时间掌握最新技术动态

关注公众号
第一时间获取最新技术文章

添加微信
技术交流 · 问题答疑 · 学习指导
评论讨论
欢迎留下你的想法和建议