Go小白入门5 - 数组 & 切片

1. 数组

数组是相同类型 & 长度固定的一组连续数据

1.1 数组的声明和初始化

1)数组的声明
// 1-dim array
var arr [5] int
2)数组的初始化
// 1) 未指定初值 - [0 0 0 0 0]
var arr1 = [5]int{}

// 2) 显示声明初值 - [1 2 3 4 5]
var arr2 = [5]int{1, 2, 3, 4, 5}
// 不设置数组大小 - 会根据元素个数来设置数组大小
var arr3 = [...]int{1, 2, 3, 4, 5}

// 3) 下标赋初值 - [0 0 0 10 0]
var arr4 = [5]int{3: 10}

1.2 访问数组元素

var arr1 = [5]int{}

// 1) 通过索引(位置)来读取
for i := 0; i < len(arr1); i++ {
	arr1[i] = i * 10
}

// 2) range遍历数组会有两个返回值 - 数组的索引,第对应的值
for idx, value := range arr1 {
	fmt.Printf("index: %d, value: %d\n", idx, value)
}

1.3 多维数组

// multi-dim array
var 3dim [5][3][3]int

初始化

// 倒数第二行的 } 必须要有逗号,因为最后一行的 } 不能单独一行
arr1 := [3][4]int{
	{0, 1, 2, 3},
	{4, 5, 6, 7},
	{8, 9, 10, 11},
}

// 或者
arr2 := [3][4]int{
	{0, 1, 2, 3},
	{4, 5, 6, 7},
	{8, 9, 10, 11}}

1.4 数组作为函数参数

Go语言在传递数组时会对其进行拷贝。如果传递的是大数组,会非常占内存,所以一般很少直接传递一个数组。

  • 传递数组的指针
  • 传递切片
  • 定义了长度的数组只能传给限制了相同数组长度的函数 => 值传递,函数中的修改对调用者不可见
  • 未定义长度的数组(切片)只能传给不限制数组长度的函数 => 切片包含对底层数组内容的引用,类似指针传递,函数中的修改对调用者可见
package main

import "fmt"

func main() {
	arr1 := [5]int{1, 2, 3, 4, 5}
	setArray1(arr1)
	fmt.Println(arr1) // [1 2 3 4 5]

	arr2 := []int{1, 2, 3, 4, 5}
	setArray2(arr2)
	fmt.Println(arr2) // [5 2 3 4 1]
}

func setArray1(params [5]int) {
	params[0], params[len(params)-1] = params[len(params)-1], params[0]
}

func setArray2(params []int) {
	params[0], params[len(params)-1] = params[len(params)-1], params[0]
}

1.5 指针数组和数组指针

1)指针数组
  • Go语言中数组默认是值传递,所以如果在函数中修改传递过来的数组对原来的数组是没有影响的
  • 指针的数组:一个数组里装的都是指针
  • 初始化时如果直接a[i] = &i,那么指针数组内部存储的全是同一个地址,输出结果也一定是相同的
  • 数组的参数传递仍是复制的形式(值传递)。但因为数组中每个元素是一个指针,所以函数复制的新数组中的值仍然是这些指针指向的具体地址值,这时改变a[1]存储空间地址指向的值,那么原实参指向的值也会变为2。
package main

import "fmt"

func main() {
	// 1) 初始化
	var arr [5]*int
	for i := 0; i < 5; i++ {
		temp := i
		arr[i] = &temp
	}
	fmt.Println(arr) // [0xc000014090 0xc000014098 0xc0000140a0 0xc0000140a8 0xc0000140b0]

	// 2) 输出
	for i := 0; i < 5; i++ {
		fmt.Print(*arr[i], " ") // 0 1 2 3 4
	}
	fmt.Println()

	// 3) 在函数中修改传递过来的数组
	setArray(arr)
	// 4) 输出
	for i := 0; i < 5; i++ {
		fmt.Print(*arr[i], " ") //0 2 2 3 4
	}
}

func setArray(params [5]*int) {
	*params[1] = 2
}
2)数组指针(指向数组的指针)

虽然main和setArray中的arrPtr是不同的指针,但是它们都指向同一块数组的内存空间,所以无论在main函数还是在setArray函数中对数组的操作都会直接改变数组

package main

import "fmt"

func main() {
	var arr [5]int
	// 或 aPtr := &a
	var arrPtr *[5]int
	arrPtr = &arr

	fmt.Println(arrPtr) //&[0 0 0 0 0]
	setArray(arrPtr)
	fmt.Println(arrPtr) //&[0 2 0 0 0]
}

func setArray(params *[5]int) {
	params[1] = 2
}

2. 切片

  • 切片操作与数组类似,但是它的长度不固定 - 可以追加元素,如果已达到当前切片容量的上限会再自动扩容
  • 切片操作"包左不包右"

2.1 切片的初始化

len()cap()获取切片的长度和容量

package main
import "fmt"

func main() {

	var slice1 = []int{} //[] 0 0
	var slice2 = []int{1, 2, 3, 4, 5} //[1 2 3 4 5] 5 5
	var slice3 = make([]int, 5) //[0 0 0 0 0] 5 5
	var slice4 = make([]int, 5, 10) //[0 0 0 0 0] 5 10

	fmt.Println(slice1, len(slice1), cap(slice1))
	fmt.Println(slice2, len(slice2), cap(slice2))
	fmt.Println(slice3, len(slice3), cap(slice3))
	fmt.Println(slice4, len(slice4), cap(slice4))
}

2.2 切片的基本操作

1)切片扩充

b = append(b, 4)

package main
import "fmt"

func main() {
	a := []int{1, 2, 3}
	b := a[1:3]

	b = append(b, 4)
	b = append(b, 5)
	b = append(b, 6)

	fmt.Println(a) // [1 2 3]
	fmt.Println(b) // [2 3 4 5 6]
}
2)切片拼接

a = append(a, b...)

package main
import "fmt"

func main() {
	a := []int{1, 2, 3}
	b := a[1:3]

	fmt.Println(b) // [2 3]

	a = append(a, b...)
	fmt.Println(a) // [1 2 3 2 3]
}
3)切片的值复制
package main
import "fmt"

func main() {
	a := []int{1, 2, 3}
	b := make([]int, 3)

	copy(b, a) // The value of a is copied to be

	fmt.Println(a) // [1 2 3]
	fmt.Println(b) // [1 2 3]
}
4)删除元素、插入元素 & 插入切片
package main
import "fmt"

func main() {
	a := []int{1, 2, 3, 4, 5}

	// 1) 删除处于索引1的元素
	fmt.Println(append(a[:1], a[2:]...))

	a = []int{1, 2, 3, 4, 5}
	// 2) 在索引1的位置插入元素1
	// 用append(append(a[:1], 1), a[1:]...) 不正确, 会改变a的取值
	fmt.Println(append(a[1:], append(a[:1], 1)...))

	a = []int{1, 2, 3, 4, 5}
	// 3) 在索引1的位置插入长度为 3的新切片
	fmt.Println(append(a[:1], append([]int{0, 0, 0}, a[1:]...)...))
}

2.3 切片 VS 数组

  • 对任何一个切片,都有一个底层数组与之对应
  • 可将切片看作是一个窗口,透过这个窗口可以看到底层数组的一部分元素

2.1 切片的容量

可以把容量当做成总长度减去左指针走过的元素值

2.2 修改切片

1)切片上再做切片,它们会指向相同的底层数组吗?

2)修改其中一个切片会影响其他切片的值么?

3) 其中一个切片扩容到容量大小之后会更换底层数组,那么之前的其他切片也会指向新的底层数组吗?不会

package main

import "fmt"

func main() {
	a := []int{1, 2, 3, 4, 5}

	b := a[1:4]
	c := b[1:3]
	fmt.Println(a, b, c) //[1 2 3 4 5] [2 3 4] [3 4]

	c[1] = 9
	fmt.Println(a, b, c) //[1 2 3 9 5] [2 3 9] [3 9]

	c = append(c, []int{10, 10, 10, 10}...)
	fmt.Println(a, b, c) //[1 2 3 9 5] [2 3 9] [3 9 10 10 10 10]
}

3. 参考资料

  1. Go菜鸟教程
  2. Datawhale组队学习
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值