08 go语言(golang) - 数据类型:数组、切片

embedded/2024/12/27 2:55:30/

数据类型

Go语言提供了一组丰富的数据类型,涵盖了基本的数值类型、复合类型和特殊类型。

基本数据类型

  1. 布尔型

    • bool:表示真或假(truefalse)。
  2. 数值型

    • 整型:包括有符号和无符号整数。

      • 有符号整型:int8, int16, int32, int64
      • 无符号整型:uint8, uint16, uint32, uint64
      • 特殊整型:int, uint(根据不同平台,大小可能为32位或64位)
      • 字节相关别名:byte(等同于 uint8),用于表示单个字节;rune(等同于 int32),用于表示Unicode码点。
    • 浮点数:

      • 单精度浮点数:float32
      • 双精度浮点数:float64
    • 复数:

      • 复数有两个部分组成,实部和虚部。
        • 单精度复数:complex64
        • 双精度复数: complex128
  3. 字符串

    • 使用双引号包裹的一串字符,可以包含任何有效的UTF-8编码字符。

派生/复杂数据类型

  1. 指针
    指向某个值的内存地址。使用方式类似C语言,但不支持指针运算。

  2. 数组
    固定长度且元素具有相同类型的集合,例如 [5]int.

  3. 切片 (Slice):
    动态大小、可变长度序列,是对数组的一个抽象层,例如 []int.

  4. 映射 (Map):
    键值对集合,用于存储键到值之间映射关系,例如 map[string]int.

  5. 结构体 (Struct):
    聚合多个字段的数据结构,每个字段可以是不同的数据类型。

  6. 接口 (Interface):
    定义一组方法签名,实现多态行为。

  7. 通道 (Channel):
    用于goroutine之间通信,通过管道发送和接收消息。

特殊数据类型

  1. 空接口 (interface{}):
    可以持有任何其他具体或抽象数据对象,因为它不包含任何方法集。

  2. 函数字面量 (func) :
    可以将函数作为变量进行传递或者返回,并且支持闭包特性。

其中的基本数据类型和指针,之前的文章已经了解过了,接下来展开其余的数据类型学习

数组

数组是一种固定长度且元素类型相同的数据结构。

特性

  1. 固定长度

    • 数组的长度在声明时就确定,并且不能改变。
  2. 元素类型相同

    • 数组中的所有元素必须是相同的数据类型。
  3. 零值初始化

    • 未显式初始化的数组会被自动赋予该类型的零值(如int为0,bool为false)。

声明和初始化

  • 声明、初始化数组

    package mainimport ("fmt""testing"
    )func Test1(t *testing.T) {// 创建一个数组,默认初始化元素都为0var arr1 [5]intarr2 := [5]int{1, 2, 3, 4, 5} // 使用字面量进行初始化arr3 := [...]int{1, 2, 3} // 使用省略号让编译器推断长度//arr := []int{1, 2, 3, 4} // 注意这是切片,不是数组!fmt.Println(arr1)fmt.Println(arr2)fmt.Println(arr3)
    }
    
  • 多维数组

    可以创建多维数组,例如二维、三维等。

    func Test2(*testing.T) {var matrix1 [3][4]int // 三行四列的二维整型数组matrix2 := [2][2]int{{1, 2}, {3, 4}} // 初始化二维矩阵//matrix3 := [2][...]int{{1, 2}, {3, 4}} // 使用省略号 ... 来推断长度仅适用于一维数组。fmt.Println(matrix1)fmt.Println(matrix2)
    }
    

访问和修改元素

func Test3(t *testing.T) {arr := [...]string{"1", "2", "a", "b"}fmt.Println(arr)arr[0] = "3" // 修改第一个元素为10fmt.Println(arr)/*修改数组长度,arr类型已确定为4个长度,无法修改为5的长度cannot use [5]string{…} (value of type [5]string) as [4]string value in assignment*///arr = [5]string{"x", "x", "x", "x", "x"}arr = [...]string{"x1", "x2", "x3", "x4"}fmt.Println(arr)value := arr[1] // 获取第二个元素值fmt.Println(value)
}

遍历

func Test4(t *testing.T) {arr := [...]int{1, 2, 3, 4}for i := range arr {fmt.Println(arr[i])}fmt.Println("------分割线------")for _, value := range arr {fmt.Println(value)}
}

注意事项

  • 数组是值类型:将一个数组赋给另一个时,会复制整个数据。
func Test5(t *testing.T) {arr := [...]int{1, 2, 3, 4}fmt.Printf("原始数组:%v \n", arr)fmt.Println("------分割线------\n ")// 创建arr的新副本,注意不是引用,修改原始数组,不会修改copy的数组arrCopy := arrarr[0] = 99fmt.Printf("原始数组:%v \n", arr)fmt.Printf("copy的数组:%v \n", arrCopy)fmt.Println("------分割线------\n ")// 函数内对参数修改不会影响原始数据。modifyArray(arr)fmt.Printf("原始数组:%v \n", arr)
}func modifyArray(arr [4]int) {arr = [...]int{99, 99, 99, 99}
}
  • 长度是类型的一部分:不同长度的两个同类数据不能互相赋值。

  • 数组的元素可以被更改(长度和类型都不可以修改)。

  • 数组的内存地址和第一个元素的内存地址相同

    func Test6(t *testing.T) {nums := [3]int32{11, 22, 33}/*在Go语言中,数组的内存地址和第一个元素的内存地址相同,这是因为数组是一个连续的内存块,且其起始位置就是第一个元素的位置。数组结构:数组是一块连续分配的内存区域,其中每个元素按顺序排列。nums 的地址实际上是整个数组在内存中的起始地址。nums[0] 是数组中的第一个元素,因此它位于这块连续内存区域的开头。*/fmt.Printf("数组的内存地址:%p \n", &nums)fmt.Printf("数组第1个元素的内存地址:%p \n", &nums[0])fmt.Printf("数组第2个元素的内存地址:%p \n", &nums[1])fmt.Printf("数组第3个元素的内存地址:%p \n", &nums[2])
    }
    

    输出:

    数组的内存地址:0xc000090190 
    数组第1个元素的内存地址:0xc000090190 
    数组第2个元素的内存地址:0xc000090194 
    数组第3个元素的内存地址:0xc000090198 
    

切片

切片(slice)是一个灵活且功能强大的数据结构,用于处理动态数组。

特性

  1. 动态长度

    • 切片可以根据需要增长或缩减,不像数组那样固定。
  2. 引用类型

    • 切片是对底层数组的引用,因此修改切片会影响到底层数组。
  3. 零值为nil

    • 未初始化的切片默认值为 nil,长度和容量都是0。

创建与初始化

  1. 从数组创建
  2. 使用字面量创建
  3. 使用make函数创建
  4. 直接声明,会初始化为nil
func Test1(t *testing.T) {// 从数组创建arr := [5]int{1, 2, 3, 4, 5}slice1 := arr[1:4] // 包含元素2、3、4fmt.Println(slice1)fmt.Printf("slice1是否为nil:%v\n", slice1 == nil)// 使用字面量创建slice2 := []int{1, 2, 3, 4, 5}fmt.Println(slice2)fmt.Printf("slice2是否为nil:%v\n", slice2 == nil)// 使用make函数创建slice3 := make([]int, 5) // 指定长度为5fmt.Println(slice3)fmt.Printf("slice3是否为nil:%v\n", slice3 == nil)slice4 := make([]int, 5, 10) // 指定长度为5,容量为10fmt.Println(slice4)fmt.Printf("slice4是否为nil:%v\n", slice4 == nil)// 声明,但不初始化var slice5 []intfmt.Println(slice5)fmt.Printf("slice5是否为nil:%v\n", slice5 == nil)
}

打印

[2 3 4]
slice1是否为nil:false
[1 2 3 4 5]
slice2是否为nil:false
[0 0 0 0 0]
slice3是否为nil:false
[0 0 0 0 0]
slice4是否为nil:false
[]
slice5是否为nil:true

为什么打印的不是<nil>

在Go语言中,打印一个变量时,不同的类型有不同的默认格式化输出。

对于复合类型,如切片、映射、通道和接口,即使它们是nil,也会打印出表示该类型的空值的字面量。例如:

  • 切片:[]
  • 映射:map[]
  • 通道:chan []
  • 接口:<nil>(接口是唯一一个即使为nil也会打印出<nil>的复合类型)

这种打印行为是为了提供更清晰的信息,帮助开发者理解变量的状态。

操作

  • 获取长度、容量,追加元素

    func Test3(t *testing.T) {slice := make([]string, 0, 10)// 追加元素,不改变原本的切片,生成新的切片sliceNew := append(slice, "a")// 长度len() ,容量cap()fmt.Printf("slice:%v, 长度:%d,容量:%d\n", slice, len(slice), cap(slice))fmt.Printf("sliceNew:%v, 长度:%d,容量:%d\n", sliceNew, len(sliceNew), cap(sliceNew))// 如果追加操作超过了原有容量,会自动分配新的底层数组并复制旧数据。sliceNew2 := append(slice, "a", "b", "c", "d", "e", "f", "g", "h", "i", "k", "l")fmt.Printf("sliceNew2:%v, 长度:%d,容量:%d\n", sliceNew2, len(sliceNew2), cap(sliceNew2))
    }
    
  • 遍历

    for i,v:=range slice{fmt.Println(i,v)}
    

底层实现

切片结构

切片由三个部分组成:

  1. 指针

    • 指向底层数组中切片可访问部分的起始位置。
  2. 长度(len)

    • 当前切片包含的元素个数。
  3. 容量(cap)

    • 从切片起始位置到底层数组末尾之间元素总数。

底层数组

  • 切片本质上是一个对底层数组的一种视图。

  • 多个切片可以共享同一个底层数组,并且修改其中一个会影响其他共享相同数据段的切片。

    func Test4(t *testing.T) {arr := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}slice1 := arr[1:4]slice2 := arr[2:5]fmt.Println("修改前:")fmt.Println(arr)fmt.Println(slice1)fmt.Println(slice2)arr[3] = 99 // 修改数组fmt.Println("修改后:")fmt.Println(arr)fmt.Println(slice1)fmt.Println(slice2)slice1[1] = 999 // 修改切片fmt.Println("修改后:")fmt.Println(arr)fmt.Println(slice1)fmt.Println(slice2)
    }
    

动态增长

  • 当使用 append() 向切片添加元素时,如果超过了当前容量,Go会自动分配更大的内存空间来容纳新数据。
  • 新内存通常是原来容量两倍,以减少频繁分配带来的开销。
  • 数据从旧内存复制到新内存后,旧内存将被垃圾回收处理。

注意事项

  1. 效率:由于直接操作的是指针和长度信息,所以在大多数情况下,使用和传递切片比传递整个数组更加高效。

  2. 共享数据风险:多个切片引用同一底层数据时,要小心并发写操作可能导致的数据竞争问题。

数组和切片的区别

  1. 长度
    • 数组的长度是固定的,一旦声明,就不能改变。
    • 切片的长度是动态的,可以在运行时改变。
  2. 声明方式
    • 数组的声明需要指定长度:var array [5]int
    • 切片的声明不需要指定长度,可以直接使用字面量或make函数:slice := []int{1, 2, 3}slice := make([]int, 5)
  3. 内存分配
    • 数组的内存分配是连续的。
    • 切片的内存分配不一定是连续的,它们实际上指向一个底层数组。
  4. 容量
    • 数组没有容量的概念。
    • 切片有容量的概念,表示切片可以扩展到的最大长度而不会引起内存重新分配。
  5. 传递参数
    • 数组通过值传递,函数内部对数组的修改不会影响原始数组。
    • 切片通过引用传递(实际上是复制了切片结构体,仍然引用相同的数据)。
  6. 操作
    • 数组的操作较少,例如不能直接在数组上进行append操作。
    • 切片提供了丰富的内置操作,如appendcopy等。
  7. 性能
    • 数组在某些情况下可能更高效,因为其固定大小和连续性。
    • 切片由于动态特性可能引入一些开销,但通常灵活性更高。
  8. 用途
    • 数组通常用于长度已知且不变的场景。
    • 切片通常用于长度可能变化或未知的场景,它们提供了更高的灵活性。

http://www.ppmy.cn/embedded/134290.html

相关文章

Leetcode 排序链表

这段代码的算法思想是 归并排序&#xff0c;一种适合链表的排序方法。它通过递归地将链表拆分成两部分&#xff0c;分别排序&#xff0c;然后合并已排序的部分&#xff0c;从而达到整体排序的目的。以下是代码的中文解释&#xff1a; 算法步骤&#xff1a; 找到链表的中点&…

Python数据分析入门知识基础和案例(万字长文)

目录 数据分析的重要性 Python数据分析工具链 NumPy数组操作 Pandas数据结构与操作 DataFrame操作 Series操作 数据转换 数据清洗 数据分析案例 数据读取与预处理 数据分析 结果展示 Matplotlib基础绘图 线图 柱状图 散点图 PyEcharts交互式图表 可视化案例展…

大模型,多模态大模型面试问题记录【时序,Qformer,卷积,感受野,ControlNet,IP-adapter】

大模型&#xff0c;多模态大模型面试问题记录24/10/27 问题一&#xff1a;视频生成例如Sora或者视频理解internvl2模型怎么提取时序上的特征。问题二&#xff1a;Qformer介绍训练阶段一训练阶段二 问题三&#xff1a;卷积维度计算公式&#xff0c;感受野1. 卷积层输出高度和宽度…

Docker-in-Docker(DinD)

Docker-in-Docker&#xff08;DinD&#xff09;是一种在 Docker 容器内部运行 Docker 引擎的技术。这种方法允许您在一个 Docker 容器内构建和运行其他 Docker 容器。以下是 Docker-in-Docker 的工作原理及其使用场景的详细解释。 工作原理 1.1 Docker 引擎的架构 Docker 引擎…

一文总结AI智能体与传统RPA机器人的16个关键区别

基于LLM的AI Agent&#xff08;智能体&#xff09;与**RPA&#xff08;机器人流程自动化&#xff0c;Robotic Process Automation&#xff09;**两种技术在自动化任务领域中扮演着至关重要的角色。AI智能体能够借助LLM拥有极高的灵活性&#xff0c;可以实时理解和响应环境的变化…

PostgreSQL-06-入门篇-集合运算

文章目录 1. UNION 组合多个查询的结果集简介带有 ORDER BY 子句的 UNION设置样例表PostgreSQL UNION 示例1) 简单的 PostgreSQL UNION 示例2) PostgreSQL UNION ALL 示例3) 带 ORDER BY 子句 UNION ALL 示例 2. INTERSECT 取交集简介带 ORDER BY 子句的 INTERSECT 操作Postgre…

《Python游戏编程入门》注-第4章6

《Python游戏编程入门》的“轮询鼠标”内容介绍了通过轮询鼠标实现实时显示鼠标位置和按键状态的游戏。 1 游戏介绍 实时显示鼠标位置和按键状态的游戏如图1所示。 图1 实时显示鼠标位置和按键状态 从图1中可以看到&#xff0c;游戏界面主要分为上下两部分。其中&#xff0c…

前端自学资料(笔记八股)分享—CSS(4)

更多详情&#xff1a;爱米的前端小笔记&#xff08;csdn~xitujuejin~zhiHu~Baidu~小红shu&#xff09;同步更新&#xff0c;等你来看&#xff01;都是利用下班时间整理的&#xff0c;整理不易&#xff0c;大家多多&#x1f44d;&#x1f49b;➕&#x1f914;哦&#xff01;你们…