Golang数组和切片

Posted 2019ab

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang数组和切片相关的知识,希望对你有一定的参考价值。

数组的使用注意事项和细节

1.数组是多个相同类型数据的结合,一个数组一旦声明/定义了,其长度是固定的,不能动态变化。
2.var arr []int 这时arr就是一个slice切片,切片后面专门讲解。
3. 数组中的元素可以是任何数据类型,包括值类型和引用类型,但是不能混用。
4. 数组创建后,如果没有赋值,有默认值(零值)
数值类型数组:默认值为0
字符串数组:默认值为“”
bool数组:默认值为false
5. 使用数组的步骤 a.声明数组并开辟空间 b.给数组各个元素赋值(默认零值)c.使用数组
6. 数组的下标是从0开始的。
7. 数组下班必须在指定范围内使用,否则报panic:数组越界,比如var arr [5]int 则有效下表为0-4
8. Go的数组属值类型:在默认情况下是值传递,因此会进行拷贝。数组间不会相互影响
9. 如想在其他函数中,去修改原来的数组,可以使用应用传递(指针方式)
10.长度是数组类型的一部分,在传递函数参数时 需要考虑数组的长度,看下面案例


要求:生成五个数,并将其反转打印

// 思路 1.生成五个数,rand.Intn()函数  2.当我们得到随机数后,就放到一个数组 int数组 3.反转打印,交换的次数是len/2,倒数第一个和第一个元素交换,倒数第二个和第二个交换
var intArr3 [5]int
len := len(intArr3)

rand.Seed(time.Now().UnixNano())
for i := 0;i<len;i++ 
	intArr3[i] = rand.Intn(100) 

fmt.Println("交换前=",intArr3)
temp := 0
for i:=0;i<len/2;i++
	temp = intArr3[len-1-i]
	intArr3[len-1-i] = intArr3[i]
	intArr3[i] = temp

fmt.Println("交换后=",intArr3)

为什么需要切片

 先来看一个需求,我们需要一个数组用于保存学生的成绩,但是学生的个数是不确定的,请问怎么办:解决方案使用**切片**

切片的基本介绍

  1. 切片的英文是slice
  2. 切片是数组的一个引用,因此切片是引用类型,在精选传递时,遵循引用传参的机制
  3. 切片的使用和数组类似,遍历切片,访问切片的元素和求切片长度len(slice)都一样。
  4. 切片的长度是可以变化的,因此切片是一个可以动态变化的数组
  5. 切片定义的基本语法:
    var 切片名 []类型
    比如:var a [] int

切片快速入门

package main
import (
	"fmt"
)
func main()
	// 演示切片的基本使用
	var intArr [5]int = [...]int1,22,33,55,99
	// 声明/定义一个切片
	// slice := intArr[1:3]
	// l.slice 就是切片名
	// 2.intArr[1:3]表示slice引用到intArr这个数组
	// 3.引用intArr数组的起始下标为1,最后的下标为3(但是不包含3)
	slice := intArr[1:3]
	fmt.Println("intArr=",intArr)
	fmt.Println("slice 的元素是 =",slice) // 22,33
	fmt.Println("slice 的元素个数 =",len(slice)) //2
	fmt.Println("slice 的容量 =",cap(slice)) // 切片的容量是可以动态变化

切片在内存中形式

基本介绍
为了让大家更加深入的理解切片,我们画图分析一下切片在内存中是如何布局的,这是一个非常重要的知识点
画出前面的内存分布图

对上面的分析总结
1.slice的确是一个引用类型
2.slice 从底层来说,其实就是一个数据结构(struct结构体)
type slice struct
ptr *[2]int
len int
cap int

切片的使用

方式一:定义一个切片,然后让切片去引用一个定义好的数组,比如之前的案例就是这样的。

方式二:通过make来创建切片
基本语法:var 切片名 []type = make([]type,len,[cap])
参数说明:type:就是数据类型 len:大小 cap:指定切片的容量,可选,如果你分配了cap,则要求cap>=len

方式三:定义一个切片,直接就指定具体数组,使用原理类似make的方式

var strSlice []string = []string"tom","jack","mary"
fmt.Println("strSlice=",strSlice)
fmt.Println("strSlice size =",len(strSlice))
fmt.Println("strSlice cap =",cap(strSlice))

方式1和方式2的区别
方式1是直接引用数组,这个数组是事先存在的,程序员是可见的。方式2是通过make来创建切片,make也会创建一个数组,是由切片在底层进行维护,程序员是看不见的。

切片的遍历

切片的遍历和数组一样,也有两种方式

package main
import (
	"fmt"
)
func main()
	// 使用常规的for循环遍历切片
	var arr [5]int = [...]int10,20,30,40,50
	slice  := arr[1:4] // 20,30,40
	for i := 0;i<len(slice);i++
	    fmt.Printf("slice[%v]=%v",i,slice[i])
	
    // 使用for---range方式遍历切片
    for i,v := range slice
    	fmt.Printf("i=%v v=%v \\n",i,v)
    

切片注意事项和细节说明

用append内置函数,可以对切片进行动态追加
切片append操作的底层原理分析

  1. 切片append操作的本质就是对数组扩容
  2. go底层会创建一下新的数组newArr(安装扩容后大小)
  3. 将slice原来包含的元素拷贝到新的数组newArr
  4. slice重新引入到newArr
  5. 注意newArr是在底层来维护的,程序员不可见
  6. 切片是引用类型,所以在传递时,遵循引用传递机制。

切片的拷贝操作

切片使用copy内置函数完成拷贝,举例说明

func main()
   var a []int = []int 1,2,3,4,5
   var slice = make([]int,10)
   fmt.Println(slice)
   copy(slice,a)
   fmt.Println(slice)

string和slice

1.string底层是一个byte数组,因此string也可以进行切片处理
2.string和切片在内存的形式,以“abcd”画出内存示意图
3.string是不可变的,也就是说不能通过str[0]=‘z’方式来修改字符串
4. 如果需要修改字符串,可以先将string->[]byte/或者 []rune->修改->重写转成string.

切片生成斐波那契数列

func fbn(n int) ([]uint64)
	// 声明一个切片,切片大小n
	fbnSlice := make([]uint64,n)
	// 第一个数和第二个数的斐波那契 为1
	fbnSlice[0] = 1
	fbnSlice[1] = 1
	// 进行for循环来存放斐波那契的数列
	for i := 2;i<n;i++
	  fbnSlice[i] = fbnSlice[i-1] + fbnSlice[i-2]
	
	return fbnSlice

感谢大家观看,我们下次见

以上是关于Golang数组和切片的主要内容,如果未能解决你的问题,请参考以下文章

Go 语言范围(Range)

Go 语言范围(Range)

go的数组和切片初始化

Golang basic_leaming2 语言容器

Golang basic_leaming2 语言容器

golang——常用内建函数