Go复合数据类型数组和切片

2023-02-27 16:33:14 浏览数 (1)

数组

声明&&初始化数组

  • 数组声明需要指定元素及元素个数,语法格式如下
  • 数组用来存储相同唯一类型的,一组已编号且长度固定的序列

var arr_name[num] arr_type

代码语言:javascript复制
package main

import "fmt"

func main()  {
	// 写添加元素的个数
	var test [5]string
	fmt.Println(test)
	for i:=0; i< 4; i  {
		test[i 1] = "test"
	}
	fmt.Println(test)
	// 不写添加元素的个数, 动态加载列表
	var arry = [...]int{1, 2, 3, 4, 5, 6}
	fmt.Println(arry)
}
/*
结果
[ test test test test]
[1 2 3 4 5 6]
*/
  • 索引元素[下标]
代码语言:javascript复制
package main

import "fmt"

func main()  {
	var test = [...]string{"1","2","3","4"}
	fmt.Println(test[2])
}
// 结果 3
  • 索引越界报错 invalid argument: index 10 out of bounds
  • 索引越界报错,骗过编译器 panic 用一个变量表示索引
代码语言:javascript复制
package main

import "fmt"

func main()  {
	var idx = 10
	var test = [...]string{"1","2","3","4"}
	fmt.Println(test[idx])
}
// 报错 骗过编译器越界

指针数组

  • 数组的元素除了是某个类型外,还可以是某个类型的指针
  • new函数返回一个TYPE类型的数据结构划分内存并执行默认的初始化操作,然后返回这个数据对象的指针
  • 只声明不初始化,必须用new,
  • 两个数组指针直接复制
代码语言:javascript复制
package main

import "fmt"

func main()  {
	var arry1 [5] *int
	fmt.Println(arry1)
	arry1[0] = new(int)
	arry1[1] = new(int)
	arry1[2] = new(int)
	arry1[3] = new(int)
	arry1[4] = new(int)
	*arry1[0] =10
	*arry1[1] =10
	*arry1[2] =10
	*arry1[3] =10
	*arry1[4] =10
	fmt.Println(arry1)
	for i:=0; i < len(arry1); i  {
		fmt.Printf("%vn",*arry1[i])
		fmt.Printf("%vn",arry1[i])
	}

}
// 结果
/*
[<nil> <nil> <nil> <nil> <nil>]
[0xc00001e0b0 0xc00001e0b8 0xc00001e0c0 0xc00001e0c8 0xc00001e0d0]
10
10
10
10
10
*/
  • 两个数组指针复制
    • 内部存放的是指针,指向同一块地址,直接赋值,内容都一样,看起来是浅拷贝,
    • 但其实是深拷贝
    • 判定依据两个数据指针不同就是深拷贝,指针地址相同就是浅拷贝
代码语言:javascript复制
package main

import "fmt"

func main()  {
	var arry1 [3]*string
	arry2 := [3]*string{new(string), new(string), new(string)}
	fmt.Println(arry1)
	fmt.Println(arry2)
	arry1 = arry2
	fmt.Println(arry1)
	for i:=0; i < len(arry2); i   {
		fmt.Printf("%d, %v, %vn", i, arry1[i], *arry1[i])
		fmt.Printf("%d, %v, %vn", i, arry2[i], *arry2[i])
	}

}
/*
结果
[<nil> <nil> <nil>]
[0xc000014260 0xc000014270 0xc000014280]
[0xc000014260 0xc000014270 0xc000014280]
0, 0xc000014260,
0, 0xc000014260,
1, 0xc000014270,
1, 0xc000014270,
2, 0xc000014280,
2, 0xc000014280,
*/

数组指针

  • 数组是一个值类型,所有的值类型变量在赋值和作为参数传递时都将产生一次复制操作
  • 从内存和性能上来看,在函数间船队数组是一个开销很大的操作,因为无论这数组有多厂,都会完整复制,并传递给函数
  • 数组指针只需要很小传递
代码语言:javascript复制
package main

import (
	"fmt"
	"unsafe"
)

func bigArryPoint(arr *[1e6]int64)  {
	fmt.Printf("[数组指针复制:大小:%d 字节]n", unsafe.Sizeof(arr))

}

func bigArry(arr [1e6]int64){
	fmt.Printf("[数组复制:大小:%d 字节]n", unsafe.Sizeof(arr))

}

func main()  {
	var arry [1e6]int64
	bigArry(arry)
	bigArryPoint(&arry)

}
/*
[数组复制:大小:8000000 字节]
[数组指针复制:大小:8 字节]
*/

多维数组

  • 多维数组的典型用例是平面坐标(而为数组)和三维坐标(三维数组)
  • Golang的数组本身只有一个唯独,但是我们可以组合多个数组从而创建出多维数组
代码语言:javascript复制
package main

import (
	"fmt"
	"unsafe"
)

func bigArryPoint(arr *[1e6]int64)  {
	fmt.Printf("[数组指针复制:大小:%d 字节]n", unsafe.Sizeof(arr))

}

func bigArry(arr [1e6]int64){
	fmt.Printf("[数组复制:大小:%d 字节]n", unsafe.Sizeof(arr))

}

func main()  {
	arry := [4][2] int{{1, 2},{10, 20},{30, 40},{50, 60}}
	fmt.Println(arry[3])
	fmt.Println(arry[3][0])


}
/*
结果
[50 60]
50
*/

切片

  • 切片是围绕动态数据来构建的
  • 数组一旦创建就不能更改长度,但是切片可以按需求自动增长和缩小
  • 增长是使用内置的append函数来实现的
  • 缩小通过对切片的再次切片来实现
声明和初始化

var直接声明

代码语言:javascript复制
package main

import (
	"fmt"
)



func main()  {

	var s1 []int
	fmt.Println(s1)
	s1 = append(s1, 1)
	s1 = append(s1, 1)
	s1 = append(s1, 1)
	fmt.Println(s1)

	var s2 = []int{1,2,3}
	fmt.Println(s2)
}

使用make

  • make([]类型, 长度, 容量)
  • 以类型0值 容量的个数填充slice
代码语言:javascript复制
package main

import "fmt"

func main()  {
	// 使用make初始化一个长度为0的slice
	var s1 = make([]int, 0)
	s1 = append(s1, 1)
	s1 = append(s1, 2)
	s1 = append(s1, 3)
	fmt.Println(s1)
	// 使用make,初始化一个长度为5,容量为5的slice
	var s2 = make([]int, 5, 5)
	s2 = append(s2, 1)
	s2 = append(s2, 2)
	s2 = append(s2, 3)
	fmt.Println(s2)
}

/*
结果
[1 2 3]
[0 0 0 0 0 1 2 3]

*/
  • new和make对比
    • 简单说new只分配内存,make用于slice,map,和channel的初始化。
    • 对比表格

函数名

适用范围

返回值

填充值

new

new可以对所有类型进行内存分配

new返回指针

new填充零值

make

make只能创建类型(slice、map、channel)

make返回引用

make填充非零值

通过切片创建新的切片

  • 语法如下 slice[start:end:cap]
  • 其中start表示从slice的第几个元素开始
  • end控制切片的长度(end-i)
  • cap控制切片的容量,如果没有给定cap,slice的长度值,则表示到底层数组的最尾部
  • 新切片的长度 = end-start
  • 新切片的容量 = cap-start

0 人点赞