七、Go语法基础(数组和切片)

Golang中文学习文档地址

  • 数组是定长的数据结构,长度一旦指定后就不能改变。
  • 切片不是定长的,切片容量不够会自行扩容。

1 数组

  • 使用场景:事先知道要存放的数据长度,并且明确在后续的过程中,数组不需要扩容。(数组长度是定长的,在声明数组的时候就已经将数组长度确定下来,后续也无法更改数组长度
  • 类型:数组是值类型,而非引用类型,所以在函数传参的过程中,是进行整个数组的值拷贝。

1.1 数组初始化

  • 数组声明的长度只能是常量,不能使用变量。(必须明确长度)
go 复制代码
var a [10]int
  • 使用元素初始化
go 复制代码
nums := [5]int{1, 2, 3}
  • 编译器自动判断数组长度
go 复制代码
//如果省略号没有,则声明的是切片
nums := [...]int{1, 2, 3}
  • 通过new关键字生成指针
go 复制代码
//该方式得到的是一个指针
nums := new([5]int)

1.2 数组的使用

  • 获取数组元素:通过数组下标获取某个位置的元素。
go 复制代码
import "fmt"

func main() {
	nums := [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	fmt.Println(nums[0])
}
  • 修改数组元素
go 复制代码
import "fmt"

func main() {
	nums := [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	fmt.Println(nums[0])
	nums[0] = 10
	fmt.Println(nums[0])
}
//输出结果
//1
//10
  • 获取数组长度:使用内置函数len
go 复制代码
import "fmt"

func main() {
	nums := [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	fmt.Println(len(nums))
}
  • 获取数组容量:使用内置函数cap,数组中,容量和长度是一样的,但在切片中,长度和容量的值不一定一样。
go 复制代码
import "fmt"

func main() {
	nums := [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	fmt.Println(cap(nums))
}
  • 数组切割

    • 数组切割的格式:arr[startIndex:endIndex],区间为左闭右开
    go 复制代码
    import "fmt"
    
    func main() {
            nums := [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
            fmt.Println(nums[:3])  //[1 2 3]
            fmt.Println(nums[3:])  //[4 5 6 7 8 9]
            fmt.Println(nums[2:3]) //[3]
            slice := nums[:]
            fmt.Println(slice)        //[1 2 3 4 5 6 7 8 9],转换后的数组类型转变成切片类型,和原数组指向的的同一个内存地址
            slice[0] = 10             //切片元素修改,原数组也会修改
            fmt.Println("数组:", nums)  //数组: [10 2 3 4 5 6 7 8 9]
            fmt.Println("切片:", slice) //切片: [10 2 3 4 5 6 7 8 9]
    }

2 切片

2.1 切片的初始化

go 复制代码
var nums []int // 值
nums := []int{1, 2, 3} // 值
nums := make([]int, 0, 0) // 值
nums := new([]int) // 指针
  • 使用make创建切片

    go 复制代码
    nums := make([]int, 0, 0)
    • 三个参数:类型,长度,容量

    • 长度和容量的区别:

      • 长度:现有切片的元素长度。

      • 容量:切片总共能装的元素数量。

  • 切片和数组最大区别是,切片可以自动扩张容量。

  • 声明切片时,值为nil,不会为其分配内存空间。

    go 复制代码
    var nums []int //只声明,不会为其分配内存

2.2 切片的使用

  • 切片的使用和数组的使用基本一致。
  • 切片可以使用append函数为切片添加元素。
go 复制代码
import "fmt"
 
func main() {
	nums := make([]int, 1)
	nums = append(nums, 1, 2, 3, 4, 5)
	fmt.Println(nums)
}
  • 切片的自动扩容

    • golang1.18 版本之前

      • 当原来的切片容量小于1024时,新的切片容量扩容为原来的2倍。
      • 当原来的切片容量大于1024时,新的切片容量扩容为原来的1.25倍。
    • golang1.18 版本之后

      • 当原来的切片容量小于256时,新的切片容量扩容为原来的2倍。
      • 当原来的切片容量大于256时,新的切片容量扩容公式为:newcap = oldcap+(oldcap+3*256)/4

2.3 插入元素

切片的插入结合append函数。

  • 头部插入
go 复制代码
import "fmt"

func main() {
    nums := []int{1, 2}
    nums = append([]int{-2, -1, 0}, nums...)
    fmt.Println(nums)//[-2 -1 0 1 2]
}
  • 中间插入
go 复制代码
import "fmt"

func main() {
	nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	nums = append(nums[:3+1], append([]int{999, 999}, nums[3+1:]...)...)
	fmt.Println(nums)//[1 2 3 4 999 999 5 6 7 8 9]
}
  • 尾部插入
go 复制代码
import "fmt"

func main() {
	nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	nums = append(nums, 99, 100)
	fmt.Println(nums)//[1 2 3 4 5 6 7 8 9 99 100]
}

2.4 删除元素

切片的删除结合append函数。

  • 头部删除
go 复制代码
import "fmt"

func main() {
	nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	nums = append(nums[2:])
	fmt.Println(nums) //[3 4 5 6 7 8 9]
}
  • 中间删除
go 复制代码
import "fmt"

func main() {
	nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	nums = append(nums[:1], nums[2:]...)
	fmt.Println(nums)//[1 3 4 5 6 7 8 9]
}
  • 尾部删除
go 复制代码
import "fmt"

func main() {
	nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	nums = append(nums[:1])
	fmt.Println(nums)
}
  • 全部删除
go 复制代码
import "fmt"

func main() {
	nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	nums = append(nums[:0])
	fmt.Println(nums)
}

2.5 拷贝

使用copy函数。

  • 注意:确保目标切片的长度足够长。
go 复制代码
func main() {
	dest := make([]int, 15)//目标切片长度必须够长,不然无法完成完整的拷贝
	src := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	fmt.Println(src, dest)
	fmt.Println(copy(dest, src))
	fmt.Println(src, dest)
}

2.6 切片的遍历

  • for遍历
go 复制代码
import "fmt"

func main() {
	nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
	for i := 0; len(nums) > i; i++ {
		fmt.Println(nums[i])
	}
}
  • for range遍历
go 复制代码
import "fmt"

func main() {
	nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
	for i, v := range nums {
		fmt.Println("index:", i, " value:", v)
	}
}

2.7 多维切片

  • 多维切片和多维数组不一样的点在于,多维切片,每个维度需要单独遍历初始化。
go 复制代码
import "fmt"

func main() {
    square := [][]int{{1, 2}, {2, 3}, {3, 5}}
    for _, sq := range square {
       fmt.Println("square:", sq)
       for _, h := range sq {
          fmt.Print(" ", h, "")
       }
       fmt.Println()
    }
}

2.8 拓展表达式

  • 切片与数组都可以使用简单表达式来进行切割,但是拓展表达式只有切片能够使用。

  • 主要是为了解决切片共享底层数组的读写问题。需要满足关系low<= high <= max <= cap,使用拓展表达式切割的切片容量为max-low

slice[low:high:max]

  • low:开始下标
  • high:结束下标
  • max:表示新切片可以获取到最大的原切片的容量大小
  • 扩展表达式的作用

    • 问题:一个切片进行切割,得出新切片和原切片公用的底层是同一个数组,对新切片进行数据操作,会对原切片的数据进行修改。
    go 复制代码
    func main() {
        oldSlice := []int{1, 2, 3, 4, 5, 6}
        newSlice := oldSlice[2:3] //未指定切片的最大下标,默认使用就切片容量大小,此时cap:6-2=4
    
        fmt.Println(newSlice)                                      //输出新切片:[3]
        newSlice = append(newSlice, 100)                           //新切片添加元素:100
        //输出:newSlice: [3 100]  oldSlice: [1 2 3 100 5 6]
        fmt.Println("newSlice:", newSlice, " oldSlice:", oldSlice) 
    }
  • 修改:切片的切割增加max参数
go 复制代码
func main() {
       oldSlice := []int{1, 2, 3, 4, 5, 6}
       newSlice := oldSlice[2:3:3]  //指定新切片的最大下标,此时cap:3-2=1
       fmt.Println(newSlice, cap(newSlice))                       //[3] 1
       newSlice = append(newSlice, 100)                           //新切片添加元素:100
       //newSlice: [3 100]  oldSlice: [1 2 3 4 5 6]
       fmt.Println("newSlice:", newSlice, " oldSlice:", oldSlice) 
   }
  • 原理:

    当切片切割时,指定了max=3时,切割后获得的新切片的容量为1,当新切片添加新的值,此时新切片的容量不够,此时会给新切片分配一个新的数组,对新切片操作就不会修改到原切片的值。

2.9 clear函数

  • clear函数会将切片内所有的值置为零
go 复制代码
import (
    "fmt"
)

func main() {
    s := []int{1, 2, 3, 4}
    clear(s)
    fmt.Println(s)
}
相关推荐
梁梁梁梁较瘦1 天前
Go工具链
go
半枫荷1 天前
六、Go语法基础(条件控制和循环控制)
go
半枫荷2 天前
五、Go语法基础(输入和输出)
go
小王在努力看博客2 天前
CMS配合闲时同步队列,这……
go
Anthony_49263 天前
逻辑清晰地梳理Golang Context
后端·go
Dobby_054 天前
【Go】C++ 转 Go 第(二)天:变量、常量、函数与init函数
vscode·golang·go
光头闪亮亮4 天前
Golang使用gofpdf库和barcode库创建PDF原材料二维码标签【GBK中文或UTF8】及预览和打印
go
光头闪亮亮4 天前
go-fitz库-PDF文件所有页转换到HTML及从HTML中提取图片的示例教程
go
用户855651414464 天前
环信http请求失败排查
go