【Golang第5章:数组与切片】golang如何使用数组、数组的遍历和、使用细节和内存中的布局;golang如何使用切片,切片在内存中的布局,

介绍

这个是在B站上看边看视频边做的笔记,这一章是Go语言的数组与切片

Golang如何使用数组,Golang数据的遍历、切片的遍历,具体请看【文章目录】

配套视频自己去B站里面搜【go语言】,最高的播放量就是

里面的注释我写的可能不太对,欢迎大佬们指出╰(°▽°)╯

(五)、数组与切片

一、数组

1.为什么需要数组

看一个问题

一个养鸡场有 6 只鸡,它们的体重分别是 3kg,5kg,1kg,3.4kg,2kg,50kg 。请问这六只鸡的总体重是 多少?平均体重是多少? 请你编一个程序。=》数组

使用传统的方法来解决

	//传统方式
	hen1 := 3.0
	hen2 := 5.0
	hen3 := 1.0
	hen4 := 3.4
	hen5 := 2.0
	hen6 := 50.0

	totaWeight := hen1 + hen2 + hen3 + hen4 + hen5 + hen6
	avgWeight := fmt.Sprintf("%.2f", totaWeight/6) // .2f表示为浮点数并保留2为小数
	fmt.Printf("一共有%vkg,平均重量为%vkg\n", totaWeight, avgWeight)

对上面代码的说明

  1. 使用传统的方法不利于数据的管理和维护.
  2. 传统的方法不够灵活,因此我们引出需要学习的新的数据类型=>数组.

使用数组方式:

//数组方式
var hens [6]float64 //1.定义一个数组
// 2.给数组每个元素赋值元素下标是从0开始的 0-5
hens[0] = 3.0 // hens数据第1个元素hens[0]
hens[1] = 5.0 // hens数据第2个元素hens[1]
hens[2] = 1.0
hens[3] = 3.4
hens[4] = 2.0
hens[5] = 50.0 // hens数据第6个元素hens[5]
// 3.遍历数组求出总体重
totaWeight2 := 0.0 //声明变量类型或者 var totaWeight2 float64
for i := 0; i < len(hens); i++ {
	totaWeight2 += hens[i]
}
//4.求出平均体重
avgWeight2 := fmt.Sprintf("%.2f", totaWeight2/float64(len(hens))) // .2f表示为浮点数并保留2为小数
fmt.Printf("一共有%vkg,=平均重量为%vkg\n", totaWeight2, avgWeight2)

对上面代码的总结

  1. 使用数组来解决问题,程序的可维护性增加.
  2. 而且方法代码更加清晰,也容易扩展。

介绍:

数组可以存放多个同一类型数据。数组也是一种数据类型,在Go中,数组是值类型



2.数组定义和内存布局

1)数组的定义

var 数组名 [数组大小]数据类型

var a [5]int

赋初值 a[0] = 1 a[1] = 30 …

数组在内存布局(重要)

	var intArr [3]int //存放3个值的数组,当我们定义完数组后,其实数组的各个元素有默认值 0
	fmt.Println(intArr)
	fmt.Printf("intArr数组的地址=%p\nintArr[0]数组第1个元素的地址%p\nintArr[1]数组第2个元素的地址%p\nintArr[2]数组第3个元素的地址%p\n",
		&intArr, &intArr[0], &intArr[1], &intArr[2]) //数组的地址和第一个元素地址相同,数组元素的地址是连续的,int有8个字节

输出:

[0 0 0]
intArr数组的地址=0xc0000101c8
intArr[0]数组第1个元素的地址0xc0000101c8
intArr[1]数组第2个元素的地址0xc0000101d0
intArr[2]数组第3个元素的地址0xc0000101d8



	var intArr [3]int32 //存放3个值的数组,当我们定义完数组后,其实数组的各个元素有默认值 0
	fmt.Println(intArr)
	intArr[0] = 10
	intArr[1] = 20
	intArr[2] = 30
	fmt.Println(intArr)
	fmt.Printf("intArr数组的地址=%p\nintArr[0]数组第1个元素的地址%p\nintArr[1]数组第2个元素的地址%p\nintArr[3]数组第3个元素的地址%p\n",
		&intArr, &intArr[0], &intArr[1], &intArr[2]) //数组的地址和第一个元素地址相同,数组元素的地址是连续的,int32有4个字节

输出:

[0 0 0]
[10 20 30]
intArr数组的地址=0xc0000120a0
intArr[0]数组第1个元素的地址0xc0000120a0
intArr[1]数组第2个元素的地址0xc0000120a4
intArr[3]数组第3个元素的地址0xc0000120a8

总结:

  1. 数组的地址可以通过数组名来获取 &intArr
  2. 数组的第一个元素的地址,就是数组的首地址
  3. 数组的各个元素的地址间隔是依据数组的类型决定,比如 int64 -> 8 int32->4…


2)数组的使用

从终端循环输入5个成绩,保存到float64数组,并输出

	// 从终端循环输入5个成绩,保存到float64数组,并输出
	var score [5]float64

	for i := 0; i < len(score); i++ {
		fmt.Printf("请输入第%d个元素的值\n", i+1)
		fmt.Scanln(&score[i]) //从终端获取值并传入到数组
	}
	for i := 0; i < len(score); i++ {
		fmt.Printf("score[%d]=%v\n", i, score[i])
	}

四种初始化数组的方式

	//四种初始化数组的方式,可以使用类型推导num5 := [...]int{}
	var num1 [3]int = [3]int{1, 3, 4}
	fmt.Println("num1=", num1)

	var num2 = [3]int{1, 32, 1}
	fmt.Println("num2=", num2)

	var num3 = [...]int{1, 3, 1} //这里的[...]是规定写法
	fmt.Println("num3=", num3)

	var num4 = [...]int{1: 800, 0: 900, 2: 100} //指定下标元素位置
	fmt.Println("num4=", num4)



3)数组的遍历


方式 1-常规遍历:

前面已经讲过了,不再赘述。


方式 2-for-range 结构遍历

这是 Go 语言一种独有的结构,可以用来遍历访问数组的元素。


基本语法

for index, value := range array01 {
    ...
}

数组:[1:300 , 2:100 , 0:900 , 3:400]

顺序:[900,300,100,400]

第一个返回值index是数组的下标,例如:下标[0]下标[1]

第二个value是在该下标位置的值,例如:数值[900]数值,[300]

他们都是仅在for循环内部可见的局部变量

遍历数组元素的时候,如果不想使用下标index,可以直接把下标index标为下划线_进行忽略

indexvalue的名称不是固定的。即程序员可以自行指定,一般命名为indexvalue

案例:

	//for-range 结构遍历
	name := [3]string{"宋江", "吴用", "卢俊义"}
	fmt.Println(name)
	for i, v := range name {
		fmt.Printf("下标i=%v,数值v=%v\n", i, v)     //for-range方式
		fmt.Printf("name[%d]=%v\n", i, name[i]) //传统方式
	}

输出:

[宋江 吴用 卢俊义]
下标i=0,数值v=宋江
name[0]=宋江
下标i=1,数值v=吴用
name[1]=吴用
下标i=2,数值v=卢俊义
name[2]=卢俊义


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

  • 1.数组是多个相同类型数据的组合,一个数组一旦声明/定义了,其长度是固定的, 不能动态变化
func main() {
	//数组是多个相同类型数据的组合,一个数组一旦声明/定义了,其长度是固定的, 不能动态变化
	var arr01 [3]int //数组声明了类型后,只能存入声明的类型
	arr01[0] = 1
	arr01[1] = 10
	// arr01[2] = 1.1//数组声明了类型后,只能存入声明的类型
	arr01[2] = 31
	//arr01[3] = 20 //超过设定的数组长度
}

  • 2.var arr []int 这时 arr 就是一个 slice 切片,切片后面专门讲解

  • 3.数组中的元素可以是任何数据类型,包括值类型和引用类型,但是不能混用。
  • 4.数组创建后,如果没有赋值,有默认值(零值)

数值类型数组:默认值为 0

字符串数组: 默认值为 ""

bool 数组: 默认值为 false

	var arr01 [3]int
	var arr02 [3]float64
	var arr03 [3]string
	var arr04 [3]bool
	fmt.Println(arr01, arr02, arr03, arr04)

输出:

[0 0 0] [0 0 0] [  ] [false false false]

  • 5.使用数组的步骤 1. 声明数组并开辟空间 2 给数组各个元素赋值(默认零值) 3 使用数组

  • 6.数组的下标是从 0 开始的

  • 7.数组下标必须在指定范围内使用,否则报 panic:数组越界,比如 var arr [5]int 则有效下标为 0-4

在这里插入图片描述


  • 8.Go 的数组属值类型, 在默认情况下是值传递, 因此会进行值拷贝。数组间不会相互影
func test1(arr [3]int) {
	arr[0] = 88      //3.把88赋值给第一个下标[0],当前数组值为[88 22 33]
	fmt.Println(arr) //4.输出(test1)栈的arr,[88 22 33]
}
func main() {
	//Go 的数组属值类型, 在默认情况下是值传递, 因此会进行值拷贝。数组间不会相互影
	arr := [3]int{11, 22, 33} //1.赋值数组给arr,在一个(mian)栈里面,当前数组值为[11 22 33]
	test1(arr)                //2.把arr进行值拷贝,并重新生成一个(test1)栈,当前数组值为[11 22 33]
	fmt.Println(arr)          //5.输出(main)栈的arr,[11 22 33]
}

  • 9.如想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)
func test2(arr *[3]int) { //4.使用*获取arr原值
	(*arr)[0] = 88 //5.修改main下arr的第一个下标[0],当前数组值为[88 22 33]
}
func main() {
	arr := [3]int{11, 22, 33}      //1.赋值数组给arr,在一个(mian)栈里面,当前数组值为[11 22 33]
	fmt.Printf("arr地址=%p\n", &arr) //2.打印arr地址
	test2(&arr)                    //3.生成一个(test2)栈,并把arr地址传入(指针)到test2
	fmt.Println(arr)               //6.输出被指针修改过后的数组[88 22 33]
}

在这里插入图片描述


  • 10. 长度是数组类型的一部分,在传递函数参数时 需要考虑数组的长度,看下面案例

在这里插入图片描述

长度是数组的一部分,由于数组长度不一致,会编译错误



5)数组的应用案例

  • 1.创建一个 byte 类型的 26 个元素的数组,分别 放置’A’-'Z‘。使用 for 循环访问所有元素并打印 出来。提示:字符数据运算 ‘A’+1 -> 'B
func test1() {
	//1.创建一个 byte 类型的 26 个元素的数组,分别 放置'A'-'Z‘。
	//使用 for 循环访问所有元素并打印 出来。提示:字符数据运算 'A'+1 -> 'B

	//思路
	//1.声明一个数组
	//2.使用for循环,利用字符可以进行运算的特点来赋值'A'+1 -> 'B
	//3.使用for打印即可

	var myChars [26]byte
	fmt.Println('A') //ASCII表十进制的A是65
	for i := 0; i < 26; i++ {
		myChars[i] = 'A' + byte(i) //类型不匹配,A是byte类型,需要把i的int类型改为byte类型
	}

	for i := 0; i < 26; i++ {
		fmt.Printf("%c ", myChars[i]) //输出该值对应的ASCII码值
	}
}

ASCII码百度百科 (baidu.com)


  • 2.请求出一个数组的最大值,并得到对应的下标
func test2() {
	//请求出一个数组的最大值,并得到对应的下标
	//思路
	//1.声明一个数组var intArr[5] = [...]int {1, -2, 9, 43, 11, 9}
	//2. 假定第一个元素就是最大值,下标就e
	//3.然后从第一个元素开始循环比较,如果发现有更大,则交换

	var intArr = [...]int{1, -2, 9, 43, 11, 9} //1.声明一个数组
	maxVal := intArr[0]                        //2.获取数组
	maxValIndex := 0                           //3.声明变量

	for i := 0; i < len(intArr); i++ {
		if maxVal < intArr[i] { //4.判断大小如果发现有更大,则执行if内变量
			maxVal = intArr[i]
			maxValIndex = i
		}
	}
	fmt.Printf("数组最大值为:%v,其下标为:%v", maxVal, maxValIndex)
}

  • 3.请求出一个数组的和和平均值。for-range遍历
func test3() {
	//请求出一个数组的和和平均值。for-range遍历
	//思路
	//1.就是声明一个数组var intArr = [...]int{1, -1, 9, 90, 11}
	//2.求出和sum
	//3.求出平均值

	var intArr = [...]int{1, -1, 9, 90, 12}
	sum := 0                     //声明sum
	for _, val := range intArr { //使用range对数组进行遍历
		sum += val //加等所有数组内的值
	}
	fmt.Printf("sum的和为%v,平均值为%v\n", sum, float64(sum)/float64(len(intArr))) //使用len统计字符串的长度
}

  • 4.要求:随机生成五个数,并将其反转打印 , 复杂应用
func test4() {
	//要求:随机生成五个数,并将其反转打印
	//思路
	//1. 随机生成五个数,rand.Intn() 函数(rand.Intn是伪随机数)
	//2. 当我们得到随机数后,就放到一个数组int数组
	//3. 反转打印,交换的次数是len/2,倒数第1个和第1个元素交换,倒数第2个和第2个元素交换

	var intArr [5]int
	rand.Seed(time.Now().UnixNano()) //1.为了每次生成的随机数不-样,我们需要 给个seed值
	for i := 0; i < len(intArr); i++ {
		intArr[i] = rand.Intn(100) //2.为了每次生成的随机数不-样,在前面给了个seed值
	}
	fmt.Println("交换前=", intArr)

	//反转打印,交换的次数是len/2,倒数第1个和第1个元素交换,倒数第2个和第2个元素交换
	temp := 0 //做一个临时变量

	for i := 0; i < len(intArr)/2; i++ {
		temp = intArr[len(intArr)-1-i]      //3.把inArr第5个下标[4]的值赋值给临时变量
		intArr[len(intArr)-1-i] = intArr[i] //4.把inArr第1个下标[0]的值赋值给inArr第5个下标[4]的值
		intArr[i] = temp                    //5.把temp临时变量赋值给inArr第1个下标[0]的值

	}
	fmt.Println("交换后=", intArr)
}



二、切片Slice

1.为什么需要切片

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


2.切片的基本介绍

  1. 切片的英文是 slice

  2. 切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递的机制。

  3. 切片的使用和数组类似,遍历切片、访问切片的元素和求切片长度 len(slice)都一样。

  4. 切片的长度是可以变化的,因此切片是一个可以动态变化数组

  5. 切片定义的基本语法:

    var 切片名 [] 类型

    比如:var a [] int


3.切片的基本使用

演示:

func main() {
	//演示切片的基本使用
	var intArr = [...]int{23, 33, 66} //1.声明一个数组
	//定义一个切片
	/*
		slice就是切片名
		intArr[1:3]表示slice引用intArr这个数组其下标为[1]的值到这个数组下标为[3]的值,不包括下标[3]
	*/
	slice := intArr[1:2]

	fmt.Println("原数组是=", intArr)
	fmt.Println("slice切片后是=", slice)
	fmt.Println("切片后slice数组数量是=", len(slice))
	fmt.Println("切片后slice数组的容量是=", cap(slice)) //cap返回v的容量,切片会在原有的容量上预先-1,例如原数组有3个元素,其slice容量是2

}

输出:

PS D:\code\Go\src\demo\22demo\main> go run .\main.go
原数组是= [23 33 66]
slice切片后是= [33]
切片后slice数组数量是= 1
切片后slice数组的容量是= 2

4.切片在内存中形式(重要)

  • 基本的介绍:

    为了让大家更加深入的理解切片,我们画图分析一下切片在内存中是如何布局的,这个是一个非 常重要的知识点:(以前面的案例来分析)

  • 画出前面的切片内存布局

在这里插入图片描述

  • 对上面的分析图总结

    1.slice 的确是一个引用类型

    2.slice 从底层来说,其实就是一个数据结构(struct 结构体)

    type slice struct {
    ptr *[2]int
    len int 
    cap int 
    }
    

5.切片的使用

方式 1

第一种方式: 定义一个切片,然后让切片去引用一个已经创建好的数组,比如前面的案例就是这样的。

在这里插入图片描述


方式 2

第二种方式: 通过 make 来创建切片.

基本语法:var 切片名 []type = make([]type, len, [cap])

参数说明:

  • type: 就是数据类型
  • len : 大小 cap :指定切片容量,可选, 如果你分配了 cap,则要 求 cap>=len
	//演示切片的使用
	var slicetest []float64 //对于切片,必须make使用,不然没有元素值
	fmt.Println(slicetest)

	//对于切片,必须make使用
	var slice []float64 = make([]float64, 5, 10) //声明切片里面有5个元素,容量为10
	fmt.Println(slice)

	slice[1] = 10 //给切片数组进行赋值
	slice[3] = 20
	fmt.Println(slice)
	fmt.Printf("slice的大小=%v\nslice的容量=%v\n", len(slice), cap(slice))

在这里插入图片描述

对上面代码的小结:

  1. 通过 make 方式创建切片可以指定切片的大小和容量
  2. 如果没有给切片的各个元素赋值,那么就会使用默认值[int , float=> 0 ; string =>"" ; bool => false]
  3. 通过 make 方式创建的切片对应的数组是由 make 底层维护,对外不可见,即只能通过 slice 去 访问各个元素.

方式 3

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

案例演示:

	//定义一个切片,直接就指定具体数组,使用原理类似 make 的方式
	var strSlice []string = []string{"tom", "jack", "mary"}
	fmt.Println(strSlice)
	fmt.Println(len(strSlice))
	fmt.Println(cap(strSlice))

方式 1 和 2 的区别

方式1是:直接引用数组,这个数组是事先存在的,程序员是可见的。

方式2是:通过make来创建切片,make也会创建一一个 数组,是由切片在底层进行维护,程序员是看不见的。

make创建切片的示意图:

在这里插入图片描述



6.切片的遍历

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

  • 使用常规for循环遍历切片

    	//使用常规for循环遍历切片
    	var arr = [...]int{110, 20, 30, 43, 50}
    	slice := arr[1:4] //20 30 43
    	for i := 0; i < len(slice); i++ {
    		fmt.Printf("slice[%v]=%v\n", i, slice[i])
    	}
    
  • for-range 结构遍历切片

    	//for-range 结构遍历切片
    	for i, v := range slice {
    		fmt.Printf("下标i=%v 原值=%v\n", i, v)
    	}
    

7.切片的注意事项

1)切片初始化时 var slice = arr[startIndex:endIndex]

说明:从 arr 数组下标为 startIndex,取到 下标为 endIndex 的元素(不含 arr[endIndex])。



2)切片初始化时,仍然不能越界。范围在 [0-len(arr)] 之间,但是可以动态增长。

var slice = arr[0:end] 可以简写 var slice = arr[:end]

var slice = arr[start:len(arr)] 可以简写: var slice = arr[start:]

var slice = arr[0:len(arr)] 可以简写: var slice = arr[:]


3)cap 是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素。


4)切片定义完后,还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者 make 一 个空间供切片来使用。


5)切片可以继续切片[案例演示]。

	//使用常规for循环遍历切片
	var arr = [...]int{110, 20, 30, 43, 50, 60}
	slice := arr[1:4] //20 30 43
	for i := 0; i < len(slice); i++ {
		fmt.Printf("slice[%v]=%v\n", i, slice[i])
	}

	//for-range 结构遍历切片
	for i, v := range slice {
		fmt.Printf("下标i=%v 原值=%v\n", i, v)
	}

	//可以进行二次切片[20 30 43]
	slice2 := slice[1:2]
	fmt.Println(slice2)

	slice2[0] = 100                //因为arr,slIce和slice2指向的数据空间是同一个,因此slice2[0]=100,其它的都变化
	fmt.Println("slice2=", slice2) //[100]
	fmt.Println("slice=", slice)   //[20 100 43]
	fmt.Println("arr=", arr)       //[110 20 100 43 50 60]

6)用 append 内置函数,可以对切片进行动态追加

	//用 append 内置函数,可以对切片进行动态追加
	var slice []int = []int{100, 200, 300}
	fmt.Println("slice", slice) //slice [100 200 300]

	//通过append直接slice追加具体元素
	slice = append(slice, 400, 500, 600) //生产一个新的空间,先把原先的slice复制到新空间[100 200 300 0 0 0],在把追加的append复制到新空间[100 200 300 400 500 600],再用slice引用到此空间
	fmt.Println("slice", slice)          //slice [100 200 300 400 500 600]

	//通过append将切片slice追加给slice
	slice = append(slice, slice...) //...是规定写法
	fmt.Println("slice", slice)     //slice [100 200 300 400 500 600 100 200 300 400 500 600]

对上面代码的小结:

切片 append 操作的底层原理分析:

切片 append 操作的本质就是对数组扩容

go 底层会创建一下新的数组 newArr(安装扩容后大小)

将 slice 原来包含的元素拷贝到新的数组 newArr

slice 重新引用到 newArr

注意 newArr 是在底层来维护的,程序员不可见

在这里插入图片描述

在这里插入图片描述


7)切片的拷贝操作

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

	//切片的拷贝操作,这是2个独立的空间,不会相互影响
	var a []int = []int{1, 2, 3, 4, 5} //这是2个独立的空间
	var slice = make([]int, 10)

	copy(slice, a)     //把切片a里面的元素拷贝到slice切片里面
	fmt.Println(a)     //[1 2 3 4 5]
	fmt.Println(slice) //[1 2 3 4 5 0 0 0 0 0]

对上面代码的说明:

(1) copy(para1, para2) 参数的数据类型是切片

(2) 按照上面的代码来看, a和 slice 的数据空间是独立,相互不影响,也就是说 a[0]= 999, slice[0] 仍然是


8)关于拷贝的注意事项

在这里插入图片描述

说明: 上面的代码没有问题,可以运行, 最后输出的是 [1


9)切片是引用类型,所以在传递时,遵守引用传递机制。看两段代码,并分析底层原理

在这里插入图片描述



8.string 和 slice

1.string 底层是一个 byte 数组,因此 string 也可以进行切片处理 案例演示:

func main() {
	//1) string 底层是一个 byte 数组,因此 string 也可以进行切片
	str := "hello@nihao你好" // "你好"占有6个字符
	slice := str[6:]
	fmt.Println(slice) //nihao你好
}

2.string 和切片在内存的形式,以 “abcd”

在这里插入图片描述

3.string 是不可变的,也就说不能通过 str[0] = 'z' 方式来修改字符串

在这里插入图片描述

4.如果需要修改字符串,可以先将 string -> []byte / 或者 []rune -> 修改 -> 重写转成 string

func main() {
	//1) string 底层是一个 byte 数组,因此 string 也可以进行切片
	str := "hello@nihao你好" // 中文一个字占有3个字节 ,不建议有中文,会出现乱码
	slice := str[6:]
	fmt.Println(slice) //nihao你好

	//把"hello@nihao你好" =》改成  "zello@nihao你好"
	arr1 := []byte(str) //把str改为byte切片 , 改中使用[]rune切片
	fmt.Println(arr1)

	arr1[0] = 'z'      //把 h 改为 z
	str = string(arr1) // 把arr1byte切片转换为string类型
	fmt.Println(str)

	//细节,我们转成[]byte后,可以处理英文和数字,但是不能处理中文
	//原因是[]byte 字节来处理,而一个汉字,是3个字节,因此就会出现乱码
	//解决方法是将string 转成[]rune 即可
	arr2 := []rune(str)
	arr2[0] = '北'
	str = string(arr2)
	fmt.Println(str)
}

9.切片的练习题

说明:编写一个函数fbn(n int),要求完成

  1. 可以接收一个n int
  2. 能够将斐波那契的数列放到切片中
  3. 提示, 斐波那契的数列形式:
    arr[0] = 1; arr[1] = 1; arr[2]=2; arr[3] = 3; arr[4]=5; arr[5]=8
package main

import "fmt"

/*
	说明:编写一个函数`fbn(n int)`,要求完成
	1) 可以接收一个`n int`
	2) 能够将斐波那契的数列放到切片中
	3) 提示, 斐波那契的数列形式:
	   arr[0] = 1; arr[1] = 1; arr[2]=2; arr[3] = 3; arr[4]=5; arr[5]=8

	思路:
	1.声明一个函数fbn(n int) ([]uint64)
	2.编程fbn(n int) 进行for循环来存放斐波那契的数列 0 =》1  1 =》 1
*/

func fbn(n int) []uint64 { //接收main传入的参数10
	fbnSlice := make([]uint64, n) //声明一个切片,切片大小为n

	fbnSlice[0] = 1 //第一个数和第二个数的斐波那契都为1
	fbnSlice[1] = 1

	for i := 2; i < n; i++ {
		fbnSlice[i] = fbnSlice[i-1] + fbnSlice[i-2] //fbnSlice[2] = fbnSlice[1] + fbnSlice[0]
	}
	return fbnSlice
}

func main() {
	fnbSlice := fbn(10) //传入参数10,并把接收到的值赋值给fbnSlice
	fmt.Println(fnbSlice)
}

章节目录

【Golang第1~3章:基础】如何安装golang、第一个GO程序、golang的基础

【Golang第4章:函数】Golang包的引用,return语句、指针、匿名函数、闭包、go函数参数传递方式,golang获取当前时间

【Golang第5章:数组与切片】golang如何使用数组、数组的遍历和、使用细节和内存中的布局;golang如何使用切片,切片在内存中的布局

【Golang第6章:排序和查找】golang怎么排序,golang的顺序查找和二分查找,go语言中顺序查找二分查找介绍和案例

【Golang第7章:map】go语言中map的基本介绍,golang中map的使用案例,go语言中map的增删改查操作,go语言对map的值进行排序

【Golang第8章:面向对象编程】Go语言的结构体是什么,怎么声明;Golang方法的调用和声明;go语言面向对象实例,go语言工厂模式;golang面向对象的三大特性:继承、封装、多态

【Golang第9章:项目练习】go项目练习家庭收支记账软件项目、go项目练习客户管理系统项目

【Golang第10章:文件操作】GO语言的文件管理,go语言读文件和写文件、GO语言拷贝文件、GO语言判断文件是否存在、GO语言Json文件格式和解析

【Golang第11章:单元测试】GO语言单元测试

【Golang第12章:goroutine协程与channel管道】GO语言goroutine协程和channel管道的基本介绍、goroutine协

posted @ 2022-11-23 17:25  雪花凌落的盛夏  阅读(48)  评论(0编辑  收藏  举报  来源