你自学半年也搞不懂的go底层,看这篇。这篇讲 go的数组、切片、Maps

数组

1、定义数组

package main

import "fmt"

func main() {
	//定义了一个大小为3的int类型数组
	//数组在定义阶段,大小和类型就固定了
	var a [3]int    //只定义,没有初始化
	fmt.Println(a)
}

//[0 0 0]

2、使用数组

package main

import "fmt"

func main() {
	var a [3]int
	a[2]=100  //修改赋值
	fmt.Println(a)
	fmt.Println(a[0]) //取0的位置
}

//[0 0 100]
//0

3、定义并赋值

package main

import "fmt"

func main() {
	//方式一
	var a [3]int=[3]int{1,2,3}  //[1 2 3]
	//方式二
	var a =[3]int{1,2,3} 		//[1 2 3]
	//方式三
	a := [3]int{1, 2, 3}		//[1 2 3]

	//只给第2个位置设为99
	a := [3]int{2:99}		//[0 0 99]
	//指定位置设置
	a := [3]int{2:99,1:88}	//[0 88 99]
	fmt.Println(a)
}


4、数组的大小是类型的一部分

package main

import "fmt"

func main() {
	//这两个不是一个类型
	var a [2]int
	var b [3]int
	a=b
	fmt.Println(a>b)
}


5、数组是值类型(当参数传递到函数中,修改不会改变原来的值)

// go语言中,都是copy传递
	/*
	python中都是引用传递,一切皆对象,就是地址,当做参数传递是把地址传过去了
	python中比较特殊:可变类型和不可变类型
	 */


package main

import "fmt"

func main() {
	var a [3]int=[3]int{5,6,7}
	fmt.Println(a)  //[5 6 7]
	test1(a)
	fmt.Println(a)  //[5 6 7]
}

func test1(a [3]int)  {
	a[0]=999
	fmt.Println(a)  //[999 6 7]

}

6、数组长度

package main

import "fmt"

func main() {
	var a [3]int=[3]int{5,6,7}
	fmt.Println(len(a)) //3
}

7、循环数组

package main

import "fmt"

func main() {
	//方式一
	var a [3]int=[3]int{5,6,7}
	for i:=0;i<len(a);i++{
		fmt.Println(a[i])
	}

	//方式二
	//range:是一个关键字
	var a [3]int=[3]int{5,6,7}
	for i,v:=range a{
		fmt.Println(i)  //索引
		fmt.Println(v)  //数组的值
	}
	
	//方式三
	//函数如果返回两个值,必须用两个值来接收
	//range可以用一个值来接收,如果用一个值来接收,就是索引
	var a [3]int=[3]int{5,6,7}
	for i:=range a{
		fmt.Println(i)  //索引
	}
	
	//方式四
	//只取值,不取索引
	var a [3]int=[3]int{5,6,7}
	for _,v:=range a{
		fmt.Println(v)  //值
	}

}

8、多维数组

package main

import "fmt"

func main() {
	//定义一个二维数组
	var a [3][2]int  // [[0 0] [0 0] [0 0]]
	//定义并初始化
	var a [3][2]int=[3][2]int{{1,2},{4,5},{9,70}}
	a[1][0]=999  //修改值
	fmt.Println(a)  // [[1 2] [999 5] [9 70]]
}

切片

//切片是由数组建立的一种方便、灵活且功能强大的包装(Wrapper)。切片本身不拥有任何数据。它们只是对现有数组的引用。
//切片底层依附于数组

1、创建切片

package main

import "fmt"

func main() {
	//创建切片(基于一个数组创建)
	var a [9]int=[9]int{1,2,3,4,5,6,7,8,9}
	//基于数组,切出一部分成为切片
	// []int 中括号中没有东西,就是切片
	var b []int
	// 没有-1  没有步长

	b=a[0:3]  //前闭后开    //[1 2 3]
	b=a[3:6]  //前闭后开    //[4 5 6]
	b=a[:]  //前闭后开		//[1 2 3 4 5 6 7 8 9]
	b=a[3:]  //前闭后开		//[4 5 6 7 8 9]
	fmt.Println(b)			
}

2、使用切片

package main

import "fmt"

func main() {
	var a [9]int=[9]int{1,2,3,4,5,6,7,8,9}
	var b []int
	b=a[3:]  //前闭后开		//[4 5 6 7 8 9]
	fmt.Println(b[0])  // 4
}

3、切片的修改会影响底层数组,数组的修个也会影响切片。相互影响

package main

import "fmt"

func main() {
	var a [9]int=[9]int{1,2,3,4,5,6,7,8,9}
	var b []int=a[0:3]  //前闭后开

	fmt.Println(a)	//[1 2 3 4 5 6 7 8 9]
	fmt.Println(b)	//[1 2 3]
	a[0]=999
	b[2]=888
	fmt.Println(a)	//[999 2 888 4 5 6 7 8 9]
	fmt.Println(b)	//[999 2 888]
}

4、切片的长度和容量

package main

import "fmt"

func main() {
	var a [9]int=[9]int{1,2,3,4,5,6,7,8,9}
	var b []int=a[2:3]  //前闭后开  //[3]

	fmt.Println(len(b))  //1
	//切片容量是7,意思是,可以往里追加值
	fmt.Println(cap(b)) //7  还可以往后追加7个

	//容量就是原数组的长度呗?对不对?不太对。。
	b[0]=9999
	fmt.Println(a)  //[1 2 9999 4 5 6 7 8 9]
	fmt.Println(b)  //[9999]
}

5、追加值

//总结1:当切片追加值,超过了切片容量,切片容量会翻倍,在原来容量基础上乘以2
//总结2:一旦超过了原数组, 就会重新申请数组,把数据copy到新数组,切片和原数组就没有关系了
//总结3:追加值打破了原数据的容量,就不会再影响原数据


package main

import "fmt"

func main() {
	var a [9]int=[9]int{1,2,3,4,5,6,7,8,9}
	var b []int=a[2:3]  //前闭后开  //[3]
	b=append(b,1)  //追加1
	b=append(b,11,22,33,44,55) //继续追加
	fmt.Println(len(b))  //7
	fmt.Println(cap(b))  //7
	fmt.Println(b)  // [3 1 11 22 33 44 55]
	fmt.Println(a)  // [1 2 3 1 11 22 33 44 55]
	//到了数组的尾部,继续追加值
	b=append(b,999)
	fmt.Println(len(b)) // 8
	fmt.Println(cap(b))  //容量是14
	//总结1:当切片追加值,超过了切片容量,切片容量会翻倍,在原来容量基础上乘以2
	b=append(b,222,333,444,555,666,7,8)
	fmt.Println(len(b))  //15
	fmt.Println(cap(b))  //容量是14*2=28

	//总结2:一旦超过了原数组, 就会重新申请数组,把数据copy到新数组,切片和原数组就没有关系了
	fmt.Println(a)
	fmt.Println(b)
	a[8]=7777
	fmt.Println(a)
	fmt.Println(b)
}

6、通过make创建切片(底层也依附于数组)

package main

import "fmt"

func main() {
	//var a []int
	//切片零值是什么? nil类型:是所有引用类型的空值
	//fmt.Println(a)
	//if a==nil{
	//	fmt.Println("我是空的")
	//}

	//3是长度,4是容量
	//var a []int=make([]int,3,4)  //[0 0 0]
	//3是长度,3是容量
	var a []int=make([]int,3)  //[0 0 0]
	fmt.Println(a)
	fmt.Println(len(a))  //3
	fmt.Println(cap(a))  //3

	a=append(a,55)  // [0 0 0 55]
	fmt.Println(a)
	fmt.Println(len(a))  //4
	fmt.Println(cap(a))  //6
}

7、切片定义并赋初值

package main

import "fmt"

func main() {
	var a []int=[]int{1,2,3}
	fmt.Println(a)  //[1 2 3]
	fmt.Println(len(a))  //3
	fmt.Println(cap(a))	  //3
}

8、切片是引用类型,当参数传递,会修改掉原来的值

package main

import "fmt"

func main() {
	var a []int=[]int{1,2,3}
	fmt.Println(a)  // [1 2 3]
	test3(a)		
	fmt.Println(a)	// [999 2 3]
}
func test3(a []int)  {
	a[0]=999
	fmt.Println(a)  // [999 2 3]
}

9、多维切片

package main

import "fmt"

func main() {
	var a [][]int=make([][]int,2,3)
	fmt.Println(a)  //[[] []]
	fmt.Println(a[0]==nil)  //true
	//会报错
	//a[0][0]=999
	// 如何做?(for循环完成初始化)

	a[0]=make([]int,2,3)
	a[0][1]=999
	fmt.Println(a)  //[[0 999] []]
	a[1][0]=99999
	//
	////定义并赋初值用的多
	//var a [][]int=[][]int{{1,2,3},{4,5,6,7,7,8}}
	//////跟上面不一样
	//var a [][3]int=[][3]int{{1,2,3},{4,5,6}}
	//fmt.Println(a)
}

10、切片的copy

package main

import "fmt"

func main() {
	var a []int=make([]int,3,4)
	var b []int=make([]int,2,6)
	fmt.Println(a)  //[0 0 0]
	fmt.Println(b)  //[0 0]
	a[0]=11
	a[1]=22
	a[2]=33
	b[0]=999
	fmt.Println(a)  // [11 22 33]
	fmt.Println(b)  // [999 0]

	copy(b,a)  //拷贝,把a拷给b,多余的截断
	fmt.Println(b) // [11 22]
}

11、切片越界

package main

import "fmt"

func main() {
	var a []int=make([]int,3,4)
	fmt.Println(a)  //[0 0 0]
	a[0]=11
	a[1]=22

	a[2]=33
	fmt.Println(a) //[11 22 33]
	a=append(a,999) //追加
	fmt.Println(a)  //[11 22 33 999]
	//中括号取值,只能取到长度值,不能取到容联大小
	fmt.Println(a[3])  //999
	fmt.Println(a[4])  //越界报错
}

Maps

//maps:hash,字典,   key:value存储

1、map的定义和使用

package main

import "fmt"

func main() {
	//map[key类型]value类型:key的类型必须可hash,key值:数字,字符串
	//map的零值:nil   它是一个引用类型
	var a map[int]string
	fmt.Println(a)	//map[]
	if a==nil{
		fmt.Println("我是空的")  // 我是空的
	}
}

2、定义了,没有初始化,使用

package main

import "fmt"

func main() {
	//var a map[int]string
	//初始化用make
	var a map[int]string=make(map[int]string)
	//如果有,会修改,如果没有,会放入
	a[1]="lqz"	 // 设值
	a[1]="jeff"  //覆盖
	a[2]="18"

	//a["xx"] key值不能乱写

	fmt.Println(a)  //map[1:jeff 2:18]
}

3、获取元素

package main

import "fmt"

func main() {
	var a map[int]string=make(map[int]string)
	//var a map[int]int=make(map[int]int)
	fmt.Println(a[0])  //取出value值的空值  ""
	fmt.Println(a)  // map[]
}

4、判断value值是否存在

package main

import "fmt"

func main() {
	//统一的方案来判断value值是否存在
	//a[0] 可以返回两个值,一个是value值(可能为空),另一个是true或false
	var a map[int]int=make(map[int]int)
	a[0]=0
	v,ok:=a[0]
	fmt.Println(v)  //0
	fmt.Println(ok)  //true
}

5、map删除元素

package main

import "fmt"

func main() {
	var a map[int]int=make(map[int]int)
	a[1]=11
	a[2]=22
	fmt.Println(a)  //map[1:11 2:22]
	//根据key删(内置函数)
	delete(a,1)  
	fmt.Println(a) //map[2:22]
}

6、map长度

package main

import "fmt"

func main() {
	var a map[int]int=make(map[int]int)
	fmt.Println(len(a))  //0
	a[1]=11
	a[2]=22
	fmt.Println(len(a))  //2
}

7、map 是引用类型

package main

import "fmt"

func main() {
	var a map[int]int=make(map[int]int)
	a[1]=11
	fmt.Println(a)  // map[1:11]
	test(a)
	//证明是引用类型,相互改变
	fmt.Println(a)  // map[1:999]
}
func test(a map[int]int)  {
	a[1]=999
	fmt.Println(a) //map[1:999]
}

8、map的相等性

//和python的字典差不多,只能按key取值后比较

package main

import "fmt"

func main() {
	var a map[string]string=make(map[string]string)
	a["name"]="lqz"
	var b map[string]string=make(map[string]string)
	b["name"]="lqz"
	fmt.Println(a)
	fmt.Println(b)
	//不能这样判断,map只能跟nil比较
	if a["name"]==b["name"] {
		fmt.Println("相等")
	}
}

9、循环map

//range循环

package main

import "fmt"

func main() {
	var a map[string]string=map[string]string{"name":"lqz","age":"19","sex":"男"}
	for k,v:=range a{
		fmt.Println(k)  //key
		fmt.Println(v)  //value
	}
}


//map是无序的(python中字典从3.6以后有序了,3.6之前无序,底层如何实现的)

猜你喜欢

转载自www.cnblogs.com/guyouyin123/p/12753637.html