GO语言学习之路11

2022/02/02

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func test(arr *[3]int) {
	(*arr)[0] = 123
}

func test1(arr [4]int) {
}

//1.数组
//1.1数组是存放多个同一类型数据  数组是go中是值类型,指向一个数据空间
func main() {
	//1.1.1定义一个数组
	//数组必须规定长度 否则就是切片
	// var 数组名 [数组大小]数据类型
	var hens [6]float64
	fmt.Println("hens=", hens)
	fmt.Printf("%p\n", &hens)
	//数组首元素地址可以通过数组名获取(同C语言)
	//给数组每个元素赋值
	hens[0] = 3.0
	hens[1] = 5.0
	hens[2] = 1.0
	hens[3] = 3.4
	hens[4] = 2.0
	hens[5] = 50.0
	//1.1.2四种初始化数组的方式
	var arr1 [3]int = [3]int{1, 2, 3}
	var arr2 = [3]int{4, 5, 6}
	var arr3 = [...]int{7, 8, 9, 10}
	//指定元素值对应的下标
	var arr4 = [3]string{1: "tom", 0: "levi", 2: "joy"}
	var arr5 = [3]string{1: "tom~", 0: "levi~", 2: "joy~"}
	fmt.Println("arr1=", arr1)
	fmt.Println("arr2=", arr2)
	fmt.Println("arr3=", arr3)
	fmt.Println("arr4=", arr4)
	fmt.Println("arr5=", arr5)
	//1.1.3遍历数组
	var totalWeight float64
	//1.1.3.1 常规遍历
	for i := 0; i < len(hens); i++ {
		totalWeight += hens[i]
	}
	//1.1.3.2 for-range 遍历
	//基本语法
	// for index , value := range array{
	// }
	//说明
	//--> 第一个返回值index是数组的下标
	//--> 第一个返回值value是在该下表位置的值
	//--> 他们都仅在for循环内部可见的局部变量
	//--> 遍历数组元素时,如果不想使用下标index,可以使用占位符下划线 _ 标记
	//--> index和value是不固定的,但是一般推荐使用
	for _, value := range hens {
		fmt.Println(value)
	}
	for index, value := range hens {
		fmt.Printf("%d只鸡的体重是%.2f\n", index, value)
	}

	avgWeight := totalWeight / float64(len(hens)) //go内运算需要保持数据类型一致
	//如果除数是常数则没问题  如果是变量必须要数据类型一致
	fmt.Printf("总体重是: %v, 平均体重是: %.2f\n", totalWeight, avgWeight)
	//1.2数组是多个相同类型数据的组合,一个数组一旦声明/定义了,长度是固定的,不能动态变化
	var arr01 [3]int
	arr01[0] = 1
	arr01[1] = 2
	arr01[2] = 3
	//arr01[2] = 1.1  //报错,类型不匹配
	//arr01[3] = 3    //长度固定,不能动态变化,否则报越界(数组不能动态增长)

	//1.3 数组创建后,如果没有赋值,会有初始值
	// 数值(整数系列,浮点数系列) -> 0
	// 字符串                     -> ""
	// bool                       -> false

	//1.4 go的数组属于值类型,在默认情况下是值传递,因此会进行值拷贝,数组间不会相互影响
	//1.5 数组引用传递
	test(&[3]int{11, 22, 33})
	//1.6 在go中长度是数组类型的一部分,在传递函数参数时,需要考虑数组的长度
	var arr22 = [...]int{1, 2, 3, 4}
	test1(arr22)

	var byteArr [26]byte
	for i := 0; i < len(byteArr); i++ {
		byteArr[i] = 'A' + byte(i)
	}
	fmt.Println("byteArr = ", byteArr)
	for i := 0; i < len(byteArr); i++ {
		fmt.Printf("%c\n", byteArr[i])
	}
	//用for-range求和 求平均值
	var array [5]int = [...]int{1, -1, 9, 90, 12}
	sum := 0
	for _, value := range array {
		sum += value
	}
	fmt.Printf("sum = %d, avg = %d\n", sum, sum/len(array))
	//如何让平均值保留到小数点
	fmt.Printf("sum = %d, avg = %f\n", sum, float64(sum)/float64(len(array)))
	//1.7 随机生成五个数,并将其反转打印
	//rand.Intn()生成随机数
	//得到随机数,就放到一个int数组
	//反转打印, 可以直接倒叙打印, 也可以交换数据元素
	var intArr [5]int
	rand.Seed(time.Now().UnixNano())
	for i := 0; i < len(intArr); i++ {
		intArr[i] = rand.Intn(1000)
	}
	fmt.Println("intArr1 = ", intArr)
	temp := 0
	for i := 0; i < len(intArr)/2; i++ {
		temp = intArr[len(intArr)-1-i]
		intArr[len(intArr)-1-i] = intArr[i]
		intArr[i] = temp
	}
	fmt.Println("intArr2 = ", intArr)
}
package main

import "fmt"

//2.切片
//***2.1 切片的基本介绍
// 2.1.1 切片是数组的引用
// 2.1.2 切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递的机制
// 2.1.3 切片的使用和数组类似,遍历切片,访问切片的元素和求切片长度len都一样
// 2.1.4 切片的长度是可以变化的,因此切片是一个可以动态变化的数组
// 2.1.5 切片定义的基本语法
//			var 变量名 []类型
//			比如: var a[] int
func main() {
	//***2.2 切片的基本使用
	var intArr [5]int = [...]int{1, 2, 3, 4, 5}
	//声明/定义 一个切片
	slice := intArr[1:3]
	//[p1:p2] p1不写默认值是0, p2不写默认值是数组最大长度, 也可以两个都不写
	slice5 := intArr[0:5]
	fmt.Println("slice5 = ", slice5) //output: slice5 =  [1 2 3 4 5]
	//等价
	slice6 := intArr[:5]
	fmt.Println("slice6 = ", slice6) //output: slice6 =  [1 2 3 4 5]
	slice7 := intArr[0:len(intArr)]
	fmt.Println("slice7 = ", slice7) //output: slice7 =  [1 2 3 4 5]
	//等价
	slice8 := intArr[0:]
	fmt.Println("slice8 = ", slice8) //output: slice8 =  [1 2 3 4 5]

	//2.2.1 slice 就是切片名
	//2.2.2 intArr[1:3] 表示slice引用到intArr这个数组的下标为1的元素到下标为3的元素,但是不包含3
	//		起始下标为1, 终止下标为3, 但是不包含下标3
	fmt.Println("intArr = ", intArr)
	fmt.Println("slice = ", slice)
	fmt.Println("slice 元素个数是  ", len(slice))
	fmt.Println("slice 元素内容是  ", slice)
	//切片的容量是可以动态变化的 , 一般是长度的两倍,但是不一定
	fmt.Println("slice 容量是 ", cap(slice))

	//***2.3 slice的底层是一个结构体,三个部分组成
	//1. 存放引用的首个元素的地址
	//2. 存放切片的长度
	//3. 存放切片的容量

	//***2.4 切片的基本使用
	//2.4.1 定义一个切片,然后让切片去引用一个已经创建好的数组,比如前面2.2的案例
	//2.4.2 通过make来创建切片
	//		基本语法
	//		var 切片名[]type = make([]type, len, [cap])
	//make参数说明: type: 数据类型	len: 大小	cap: 指定切片容量,可选
	//如果分配了cap,则cap 必须大于或等于 len
	var slice1 []float64
	fmt.Println(slice1) // output: []
	var slice2 []float64 = make([]float64, 5, 10)
	fmt.Println(slice2) // output: [0 0 0 0 0]
	slice2[1] = 1
	slice2[2] = 3
	fmt.Println(slice2)      // output: [0 1 3 0 0]
	fmt.Println(len(slice2)) // output: 5
	fmt.Println(cap(slice2)) // output: 10
	//通过make方式创建切片可以指定切片的大小和容量
	//如果没有给切片的各个元素赋值,那么使用默认值,0, "", false
	//通过make方式创建的切片对应的数组是由make底层维护,对外不可见,只能通过slice去访问各个元素
	//2.4.3 定义一个切片,直接就指定具体数组,使用原理类似make的方式
	var slice3 []int = []int{1, 2, 3, 4, 5}
	fmt.Println("slice3 = ", slice3)
	fmt.Println("slice3 len = ", len(slice3))
	fmt.Println("slice3 cap = ", cap(slice3))

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

	//***2.5 切片的遍历
	//2.5.1 for常规遍历切片
	var numArr [5]int = [...]int{1, 2, 3, 4, 5}
	slice4 := numArr[1:4]
	for i := 0; i < len(slice4); i++ {
		fmt.Printf("slice[%v] = %v\n", i, slice4[i])
		//output:
		/*
			slice[0] = 2
			slice[1] = 3
			slice[2] = 4
		*/
	}
	fmt.Println()
	//2.5.2 for-range遍历切片
	for i, value := range slice4 {
		fmt.Printf("slice[%v] = %v\n", i, value)
		//output:
		/*
			slice[0] = 2
			slice[1] = 3
			slice[2] = 4
		*/
	}

	//***2.6 切片可以继续切片
	//操作和切数组相同

	//***2.7 切片可以使用append函数进行动态增加
	var sli1 []int = []int{1, 2, 3}
	fmt.Println("sli1 = ", sli1)
	//2.7.1 通过append直接给sli1追加具体的元素,但是元素类型要一致
	sli2 := append(sli1, 400, 500, 600)
	fmt.Println("sli2 = ", sli2)
	//2.7.2 追加过后 sli1不会变化,会拷贝到sli2
	//如果要变化本身
	sli2 = append(sli2, 111, 11, 1222)
	fmt.Println("sli2 = ", sli2)

	//2.7.3 也可以直接追加切片
	sli2 = append(sli2, sli2...) //...是固定的写法
	fmt.Println("sli2 = ", sli2)

	//***2.8 切片append的底层分析细节
	//2.8.1 切片append操作的本质就是对数组扩容
	//2.8.2 go底层会创建一个新的数组newArr(安装扩容后大小)
	//2.8.3 将slice原来包含的元素拷贝到新的数组newArr
	//2.8.4 slice重新引用到newArr
	//2.8.5 注意newArr是在底层来维护的,程序员不可见
	var t1 [5]int = [5]int{1, 2, 3, 4, 5}
	var s1 []int = t1[2:5] //3 4 5
	var s2 []int = s1[0:2]
	s2[0] = 100
	fmt.Println("t1 = ", t1) //output: t1 =  [1 2 100 4 5]
	fmt.Println("s1 = ", s1) //output: s1 =  [100 4 5]
	fmt.Println("s2 = ", s2) //output: s2 =  [100 4]

	//***2.9 切片拷贝
	var s3 []int = []int{1, 2, 3, 4, 5}
	var s4 = make([]int, 10)
	copy(s4, s3)
	fmt.Println("s3 = ", s3) //output: s3 =  [1 2 3 4 5]
	fmt.Println("s4 = ", s4) //output: s4 =  [1 2 3 4 5 0 0 0 0 0]
	s4[0] = 100
	fmt.Println("s3 = ", s3) //output: s3 =  [1 2 3 4 5]
	fmt.Println("s4 = ", s4) //output: s4 =  [100 2 3 4 5 0 0 0 0 0]
	//s3 和 s4的数据空间是独立的

	var s5 []int = []int{1, 2, 3, 4, 5}
	var s6 = make([]int, 3)
	copy(s6, s5)
	fmt.Println("s6 = ", s6) //output: s6 =  [1 2 3]
	//如果内存小于被拷贝的切片,那就拷贝满即可
}
package main

import "fmt"

//string 和 slice

func fbn(n int) []uint64 {
	//1.声明一个切片,切片大小是n
	var fbnSlice []uint64 = make([]uint64, n)
	fbnSlice[0] = 1
	fbnSlice[1] = 1
	for i := 2; i < n; i++ {
		fbnSlice[i] = fbnSlice[i-1] + fbnSlice[i-2]
	}
	return fbnSlice
}

func main() {
	//1.string底层是一个byte数组,因此string也可以进行切片处理
	var myStr string = "hello world"
	//使用切片获取world
	slice := myStr[6:]
	fmt.Println("slice =", slice)
	//2.string是不可变的,也就说不能通过string[0]='z'方式来修改字符串
	//myStr[2] = 'q' //error
	//3.如果需要修改字符串,可以先将string->[]byte 或者 []rune->修改->重写转成string
	//把 h  改为->  z

	//1.这个方法可以处理英文和数字,不能处理中文,[]byte是按字节来处理,汉字是三个字节
	arr1 := []byte(myStr)
	arr1[0] = 'z'
	myStr = string(arr1)
	fmt.Println("myStr1 =", myStr)

	//2.这个方法可以处理中文,因为[]rune是按照字符来处理的
	arr2 := []rune(myStr)
	arr2[0] = '中'
	myStr = string(arr2)
	fmt.Println("myStr2 =", myStr)

	//编写函数接收一个 n int 能够将斐波那契的数列放到切片中
	//思路
	//1.声明一个函数 fbn(n int)([]uint64)
	//2.编写fbn(n int) 进行for循环来存放斐波那契数列  0-> 1    1-> 1
	fbnSliceRet := fbn(10)
	fmt.Println("fbnSliceRet =", fbnSliceRet)
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值