当前位置: 首页 > news >正文

【Goland】:数组与切片

目录

1. 数组 (Array)

1.1 定义及特点

1.2 遍历数组

1.3 值类型特性

2. 切片 (Slice)

2.1 定义及特点

2.2 切片创建方式

2.3 切片的增删查改

2.3.1. 添加切片元素

2.3.2. 删除切片元素

2.3.3. 访问元素 / 遍历

2.3.4 修改元素

2.4 string 切片


1. 数组 (Array)

1.1 定义及特点

数组(Array)是一个由 固定长度 的、相同类型元素组成的有序集合。

var arr [N]T   // N 表示数组长度,T 表示元素类型var a [3]int                       // 长度为 3 的 int 数组,默认值为 [0 0 0]
b := [4]string{"Go", "Rust", "Java", "C++"} 
c := [...]bool{true, false, true}  // 使用 `...` 自动推断长度

特点

  • 固定长度:长度在定义时确定,无法改变。
    [3]int[4]int 属于不同类型。

  • 元素类型相同:数组中所有元素必须是相同类型。

  • 默认值机制

    • 数值类型:默认 0

    • 字符串:默认 ""

    • 布尔值:默认 false

    • 引用类型(指针、切片、map、chan 等):默认 nil

package mainimport "fmt"func main() {var a [5]intvar b [5]stringvar c [5]boolfmt.Println(a)    // [0 0 0 0 0]fmt.Println(b)    // [    ]fmt.Println(c)    // [false false false false false]
}

1.2 遍历数组

数组可以通过 下标索引for-range 遍历,在for-range循环中遍历数组时,每次迭代会返回两个值,第一个是元素的索引,第二个是元素的值

package mainimport "fmt"func main() {a := [4]string{"Go", "Rust", "Java", "C++"}for i := 0; i < len(a); i++ {fmt.Printf("%s ", a[i])}fmt.Println()for idx, val := range a {fmt.Printf("%d %s\n", idx, val)}
}

1.3 值类型特性

数组是 值类型,赋值或传参时会 拷贝整个数组,互不影响。

package mainimport "fmt"func main() {a := [4]int{1, 2, 3, 4}b := ab[0] = 100fmt.Println(a) // [1 2 3]fmt.Println(b) // [100 2 3 4]
}

如果希望在函数中对数组的操作影响到原始数组,可以通过数组指针的方式进行传参。

package mainimport "fmt"func modifyArray(arr *[4]int) {(*arr)[0] = 999arr[1] = 888
}func main() {a := [4]int{1, 2, 3, 4}modifyArray(&a) // 传入数组指针fmt.Println(a) // [999 888 3 4]
}

2. 切片 (Slice)

2.1 定义及特点

  • 切片是 动态长度的序列可变长数组,序列中每个元素类型相同。

  • 切片 引用数组 的一部分或全部元素。

  • 底层由 三部分 构成:

    1. 指针(ptr):指向底层数组起始位置

    2. 长度(len):切片中实际元素数量

    3. 容量(cap):切片从起始位置到底层数组末尾的最大容量

    var s1 []int            // []s2 := []int{1, 2, 3}    // [ 1 2 3 ]s3 := make([]int, 3, 5) // [ 0 0 0 ], 长度3,容量5

2.2 切片创建方式

方式一:指定具体数组

  • 直接初始化切片,底层数组由 Go 自动分配

  • len = 10cap = 10

  • 底层数组元素值来自指定的字面量。

    a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}fmt.Printf("类型:%T\n", s)  // 类型:[]intfmt.Println(len(s))        // 10fmt.Println(cap(s))        // 10

方式二:引用现有数组

  • 底层依赖已有数组

  • 注意:修改 slice 会影响 arr

    // slice 指针指向 arr[3]// len = 3 → 结束下标 - 起始下标// cap = 7 → 从起始下标到数组末尾的容量a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}var s = a[3:6]fmt.Printf("类型:%T, 值:%d\n", s, s) // 类型:[]int, 值:[4 5 6]fmt.Println(len(s))               // 3fmt.Println(cap(s))               // 7

方式三:make 函数

  • 底层数组由 make 在堆上分配

  • 未赋值时使用类型默认值(如 int → 0, string → "", bool → false)。

    // len = 5 → 元素个数// cap = 10 → 底层数组容量s := make([]int, 5, 10)fmt.Println(s)      // [0 0 0 0 0]fmt.Println(len(s)) // 5fmt.Println(cap(s)) // 10

2.3 切片的增删查改

2.3.1. 添加切片元素

newSlice := append(oldSlice, elem1, elem2, ...)
// 第一个参数:目标切片
// 后续参数:要追加的一个或多个元素(可变参数)
// 返回值:一个新的切片(可能和原切片底层数组相同,也可能不一样)

一、容量够用

  • 如果 oldSlicecap 足够容纳新元素 → 直接写入原来的底层数组。
  • 新切片和旧切片共享底层数组,修改会互相影响。
package mainimport "fmt"func main() {s1 := make([]int, 3, 5)s1[0], s1[1], s1[2] = 1, 2, 3s2 := append(s1, 4)fmt.Println(s1) // [1 2 3]fmt.Println(s2) // [1 2 3 4]//  修改s1的s1[0],结果s2的s2[0]也改变了s1[0] = 100fmt.Println(s1) // [100 2 3]fmt.Println(s2) // [100 2 3 4]
}

二、容量不足

如果 cap 不够 → Go 运行时会:

  1. 重新分配一个更大的底层数组(通常是原来的 2 倍,但不固定)

  2. 把旧数据复制到新数组

  3. 把新元素放进去

  4. 返回一个新的切片(和旧切片不再共享底层数组)

package mainimport "fmt"func main() {s1 := make([]int, 3, 3)s1[0], s1[1], s1[2] = 1, 2, 3s2 := append(s1, 4)fmt.Println(s1) // [1 2 3]fmt.Println(s2) // [1 2 3 4]//  修改 s1 的 s1[0],s2 的 s2[0] 不会改变了s1[0] = 100fmt.Println(s1) // [100 2 3]fmt.Println(s2) // [1 2 3 4]
}

三、追加另一个切片

package mainimport "fmt"func main() {s1 := []int{1, 2, 3}s2 := []int{4, 5, 6}s3 := append(s1, s2...)fmt.Println(s3) // [1 2 3 4 5 6]
}

四、在中间插入元素

Go 没有直接的 insert,需要用切片拼接:

package mainimport "fmt"func main() {s1 := []int{1, 2, 3}i := 1s3 := append(s1[:i], append([]int{100}, s1[i:]...)...)fmt.Println(s3) // [1 100 2 3]
}

2.3.2. 删除切片元素

Go 也没有内置 delete,常见的写法是用切片拼接。

    // 删除下标为2s1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}s3 := append(s1[:2], s1[3:]...)fmt.Println(s3)    // [1 2 4 5 6 7 8 9 10]// 删除开头的元素s1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}s3 := append(s1[1:])fmt.Println(s3) // [2 3 4 5 6 7 8 9 10]// 删除末尾的元素s3 := append(s1[:len(s1)-1])fmt.Println(s3) // [1 2 3 4 5 6 7 8 9]

2.3.3. 访问元素 / 遍历

    s1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}// 按下标访问fmt.Println(s1[4]) // 5fmt.Println(s1[6]) // 7// 遍历for i, v := range s1 {fmt.Println(i, v)}for i := 0; i < len(s1); i++ {fmt.Println(s1[i])}

2.3.4 修改元素

s := []int{1, 2, 3}
s[1] = 99
fmt.Println(s) // [1 99 3]

2.4 string 切片

  • 在 Go 中,string 本质上是一个 只读的字节序列(byte slice)。也就是说,string 底层是 不可变的 []byte。一旦创建,里面的内容不能被修改。

  • string 是不可变的,修改字符串必须转换为 []byte[]rune

  • 切片操作不会复制数据,只是产生一个新的 string(仍然只读)。

  • []byte 适合 ASCII/英文[]rune 适合中文或其他 Unicode 字符

    s := "hello"s1 := s[1:]fmt.Println(s)  //hellofmt.Println(s1) // ellos[0] = '1'  // 无法直接修改

修改字符串的方法

因为 string 不能直接修改,所以必须转换为 可变类型[]byte[]rune):

	s := "hello"a := []byte(s)a[0] = 'x'fmt.Println(string(a)) // xello        s := "我爱中国"a := []rune(s)a[0] = '你'fmt.Println(string(a))   // 你爱中国

http://www.dtcms.com/a/338269.html

相关文章:

  • 【25-cv-09352】Maradona 品牌维权,从球衣到周边全品类侵权高危
  • Jupyter 中实现交互式图表:ipywidgets 从入门到部署
  • 【数据集】全球大气监测计划(GAW)简介
  • 用户认证技术与HTTP协议
  • 基于pychrm工具的python读取 USB 摄像头(实时+保存录像+摄像头信息打印+镜像)—— OpenCV库
  • 【React Hooks】封装的艺术:如何编写高质量的 React 自-定义 Hooks
  • 【高等数学】第九章 多元函数微分法及其应用——第七节 方向导数与梯度
  • Localhost和127.0.0.1
  • 数据库原理及应用_数据库基础_第2章关系数据库标准语言SQL_数据类型表操作(定义、操作和修改)
  • 终极方案!lightRag/graphRag离线使用tiktoken持续报错SSLError,不改源码,彻底解决!
  • MySQL和HiveSQL在查询上的区别
  • 上网行为管理
  • 用户认证与应用控制技术
  • 深入浅出 SQL:数据库操作的核心语言完全指南
  • 【c++】从灵活到规范:自定义消息机制的设计与实践
  • day10(练习题)
  • Three.js 动画循环学习记录
  • 6 webUI中图生图重绘方式--涂鸦、涂鸦重绘、局部重绘、上传蒙版重绘
  • 生成式引擎优化(GEO)AI搜索优化专家竞争力报告
  • 检测手绘图中不规则曲线交点的方法和一般规则线条交点的方法
  • rom定制系列------小米cc9机型 原生安卓15系统 双版线刷root 定制修改功能项
  • 力扣(分发糖果)
  • 【完整源码+数据集+部署教程】海洋垃圾与生物识别系统源码和数据集:改进yolo11-RVB
  • 深度优先遍历dfs(模板)
  • VS Code Copilot 完整使用教程(含图解)
  • 【笔记ing】考试脑科学 脑科学中的高效记忆法
  • 图论:Floyd算法
  • 从数学原理推导的角度介绍大语言MOE架构的本质
  • Linux系统WireShark抓取本地网卡报文
  • uv 现代化的虚拟环境管理工具