第4课:Go 数据类型详解

【腾讯云】语音识别准确率高,支持多语种,多场景,限时特惠,最低14.9元起

推广

【腾讯云】语音识别准确率高,支持多语种,多场景,限时特惠,最低14.9元起

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语言的数据类型:

  1. 数组:固定长度,值类型
  2. 切片:动态长度,引用类型,基于数组
  3. 映射:键值对存储,引用类型
  4. 结构体:自定义类型,组合数据
  5. 接口:定义行为,实现多态
  6. 指针:内存地址,引用传递

下一课预告

在下一课中,我们将学习Go语言的函数和方法,包括:

  • 函数的高级特性
  • 方法的定义和使用
  • 接口的深入应用
  • 错误处理机制

💡 小贴士:理解值类型和引用类型的区别是掌握Go语言的关键,多练习指针和接口的使用。

Vue3 + TypeScript 企业级项目实战

课程推荐

Vue3 + TypeScript 企业级项目实战
Python 全栈开发工程师培训

热门课程

Python 全栈开发工程师培训

📚 文章对你有帮助?请关注我的公众号,万分感谢!

获取更多优质技术文章,第一时间掌握最新技术动态

关注公众号

关注公众号

第一时间获取最新技术文章

添加微信

添加微信

技术交流 · 问题答疑 · 学习指导

评论讨论

欢迎留下你的想法和建议