20200325 switch,数组,切片与map
昨日回顾
// 函数
函数 func 函数名(参数1 类型, 参数2 类型)(返回值类型,返回值){函数体}
https://saohu156.com
只有一个返回值
如果只有return,后面什么都不写,相当于无返回值
可变长参数, func 函数名(参数1, ...类型)(){函数体}
匿名函数:没有名字的函数(必须定义在函数内部) func()(){}
函数的类型: 函数的参数,返回值都是类型的一部分
内层函数的返回 main函数中调用 接受需要先定义变量的类型
闭包: 定义在函数内部,对外部组用于有引用 >> 闭包多了一种给函数传参的方式
赋返回值,如果有一个或多个,不接受
// if-else
if 初始值;条件{
}else if 条件{
}else{
}
// for: go中只有for循环
for 第一部分初始化;第二部分条件;第三部分自增/自减 i+=2/i=i+2{循环体内容}
break
continue
go进阶
1. switch
使用
多条件判断,用于替换if else
func main() {
var a=11
switch a{
case 8:
fmt.Println("8")
case 9:
fmt.Println("9")
case 10:
fmt.Println("10")
default: //上面的条件都不符合的话,执行
fmt.Println("我不知道")
}
}
多条件
func main() {
var a=11
switch a{
case 7,8,9:
fmt.Println("8")
case 10,11,12:
fmt.Println("9")
case 13,15:
fmt.Println("10")
default: //上面的条件都不符合的话,执行
fmt.Println("我不知道")
}
}
无表达式
func main() {
var a=test() //判断一个函数的执行结果
switch { //不加表达式
case a==8:
fmt.Println("8")
case a==100:
fmt.Println("100")
case a==80:
fmt.Println("80")
case a ==10 || a==11:
fmt.Println("这就是or")
default: //上面的条件都不符合的话,执行
fmt.Println("我不知道")
}
}
and与or
and &&
or ||
Fallthrough
无条件执行下一个case中的代码
func main() {
var a=test() //判断一个函数的执行结果
switch { //不加表达式
case a==8:
fmt.Println("8")
fallthrough // 无条件执行下一个case中的代码
case a==100:
fmt.Println("100")
fallthrough // 无条件执行下一个case中的代码
// break 其他语言的不加break就是fallthrough
default: //上面的条件都不符合的话,执行
fmt.Println("我不知道")
}
}
2. 数组array
数组是同一类元素的集合,类似于python中的列表(列表中可以放任意元素)
python中为什么能放任意类型的元素
python中一切皆对象,对象是一个引用(内存地址)
数组:
定义了一个长度为3的int类型数组
每一格的所占内存都是一样大小的,所有类型必须一致(连续存储的同一类元素)
数组的声明
数组有大小,放的数据类型. 定义阶段长度固定了,以后不能改
func main(){
// 定义了一个长度为3的int类型数组
var a [3]int
fmt.Println(a) // 打印 [0 0 0]
// 定义了一个长度为5的string类型数组
var a [5]string
fmt.Println(a) // 打印 [ ]
}
------------------------------------------------------------
int 默认值是 0
string 默认值是 ""
bool 默认值是false
数组 默认值 跟他的数据是有关系的,数组存放类型的空值
定义并初始化
func main(){
// 三种方式
var a [3]int = [3]int{1,2,3}
var a=[3]int{1,2,3}
a :=[3]int{1,2,3}
// 使用
fmt.Println(a[2])
}
例子
// 只想把第29个位置设置为1,其他都是0
func main(){
var a [30]int=[30]int{28:1,29:9999}
fmt.Println(a)
}
// 使用...
func main(){ // 数组在定义阶段就是固定长度的,所以没有可变长
a := [...]int{28:1,29:9999} // 这里根据最大长度设置数组 29
a := [...]int{2,3,4} // 这个长度为3
fmt.Println(a)
}
// 不能超长
数组是值类型
值类型跟引用类型相对应: 当函数传参时,传到函数内部,修改数组,不会影响原来的
-- go中的函数传参,都是copy传递 --
a:=10
test(a) //传入test中的a都是copy传递,不会对原a进行改变
引用类型: 传递过去的就是引用地址
值类型: 传递的是copy的值
-- python中可变类型与不可变类型 --
一切皆对象,都是引用
python强行将数字字符串元组做成不可变数据类型,当做函数传参时,在函数中修改.
- 不可变数据类型,不会修改原来的
- 其他的,在函数中修改,都会影响原来的
python是值传递还是引用传递
统一使用的都是引用传递
go语言中保留了指针,可以传递地址.
func main(){
var a=[3]int{2,4,6}
fmt.Println(a) // [2 4 6]
test(a)
fmt.Println(a) // [2 4 6]
}
func test(a [3]int){
x[0] = 999
fmt.Println(a) // [999 4 6]
}
数组长度len()
len
循环数组使用range 迭代数组
// 第一种: 普通循环
func main(){
var a=[3]int{2,4,6}
for i:=0;i<len(a);i++{
fmt.Println(a[i])
}
}
// 第二种:使用range :range不是一个内置函数,他是一个关键字
i := range a i是索引,一个值来接受,就是索引
i,v := range a i是索引,两个值来接受,索引与值
_,v := range a 使用_来不接受索引,只接受值
// 索引
var a =[3]int{2,3,4}
for i := range a{
fmt.Println(i)
}
// 索引与值
var a =[3]int{2,3,4}
for i,v := range a{
fmt.Println(i)
fmt.Println(v)
}
// 值
var a =[3]int{2,3,4}
for _,v := range a{
fmt.Println(v)
}
多维数组
数组套数组
定义并初始化
var a [3][3]int = [3][3]int{1,2,3}{2,3,4}{5,6,7}
使用
var a[3][3]int
a[0][1]=999
fmt.Println(a)
// [ [0 999 0] [0 0 0] [0 0 0]]
// 三维数组
var a [3][3][3]int
fmt.Println(a)
数组的大小是类型的一部分
var a[3]int
var a[4]int
// 只要数组不一样,他们的类型就不一致
3. 切片 slice
由于go中的数组类型,其长度是固定的,无法改变。在很多场景下我们需要动态改变数组的长度,因而go中内置了slice类型,称其为数组的一种抽象(可看作是动态数组)。slice与数组很相似,只是长度可变,可追加元素
切片是由数组建立的一种方便灵活功能强大的包装
切片本身不拥有任何数据,只是对现有数据的引用
1. 切片的初始化
切片初始化的三种方式
- 通过make函数
- 通过字面量方式
- 对源数组或源切片使用
identifier[start:end]
语法生成切片
package main
import (
"fmt"
)
func main() {
//make切片
var s0 []int = make([]int,3,5) //切片类型、切片长度、切片容量
fmt.Println(len(s0),cap(s0),s0)
//--> 3 5 [0 0 0]
//字面量切片
var s1 []int = []int{1,2,3} //切片的元素
fmt.Println(len(s1),cap(s1),s1)
//--> 3 3 [1 2 3]
//从数组切片,这里先定义一个数组a
var a [10]int
s2 := a[:3] //从数组a的第0个到第3个元素生成切片
fmt.Println(len(s2),cap(s2),s2)
//--> 3 10 [0 0 0]
//从s2切片
s4 := s2[:2]
fmt.Println(len(s4),cap(s4),s4)
//-->2 10 [0 0]
}
func main(){
// 1.创建一个切片
// 先创建一个数组
var a [10]int=[10]int{1,2,3,4,5,6,7,8,9,10}
// 创建切片(基于上面数组的切出来)
var b = a[:] //从0切到最后
var b = a[5:] // 从第5切到最后
var b = a[5:9] //前闭后开,从第5个到第9个
}
通过make函数
切片类型:
中括号有东西就是数组,没有东西就是数组
var b[]int = a[5:9]
2.切片的修改
切片的修改会影响原来的数据,数组的修改也会影响切片
var a [10]int=[10]int{1,2,3,4,5,6,7,8,9,10}
var b[]int = a[5:9]
b[0] = 999 // 切片影响数组
a[6] = 888 // 数组影响切片
fmt.Println(b) // [999 7 8 9 ]
fmt.Println(b) // [1 2 3 ... 999 7 ...]
3. 切片的长度和容量
切片的长度就是它所包含的元素个数。
切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数
切片 s
的长度和容量可通过表达式 len(s)
和 cap(s)
来获取。
长度 len()
var a [10]int=[10]int{1,2,3,4,5,6,7,8,9,10}
var b[]int = a[5:9]
len(b) // 4
容量 cap()
总共能放多少值(追加元素)
cap(b) // 6
s := []int{1,2,3,4,5}
fmt.Println(s,len(s),cap(s)) // [1 2 3 4 5] 5 5
s = s[2:3]
fmt.Println(s,len(s),cap(s)) // [3] 1 3
//此时的s就是 [3] 以此为基础访问0:3 打印出 [3 4 5]
s = s[0:3]
fmt.Println(s,len(s),cap(s)) // [3 4 5] 3 3
//var a [10]int=[10]int{1,2,3,4,5,6,7,8,9,10}
////var b[]int =a[5:9]
////var b[]int =a[0:3]
//var b[]int =a[2:3]
//fmt.Println(len(b))
//fmt.Println(cap(b))
4. 使用make创建一个切片
切片的空值:
nil
类型(引用类型的控制都是nil)
var a []int
fmt.Println(a)
if a==nil{
fmt.Println("a是nil")
}
// a[0]=100 直接报错,不可更改
make
make是内置函数
- 第一个参数写类型
- 第二个参数是切片的长度
- 第三个参数是切片的容量
var a []int=make([]int,3,4)
fmt.Println(a) // [0 0 0]
a[0] = 999
fmt.Println(a) // [999 0 0]
// 中括号只能取长度
a[2] = 888
// 容量如果不传,和长度一样
var a []int=make([]int,3)
5. 追加切片元素
基于make
var a []int=make([]int,3,4)
// 在最后追加一个元素 999
a = append(a,999)
fmt.Println(a) // [0 0 0 999]
fmt.Println(len(a)) // 4
fmt.Println(cap(a)) // 4
//再追加一个
a = append(a,888)
// 不会报错,追加的时候,一旦超出容量,会重新创建一个数组,让切片指向新的数组,新数组大小是原来的切片容量的两倍
fmt.Println(a) // [0 0 0 999 888]
fmt.Println(len(a)) // 5
fmt.Println(cap(a)) // 8
切片如果基于数组切出来
var a [10]int=[10]int{1,2,3,4,5,6,7,8,9,10}
var b[]int = a[5:9]
b =append(b,777)
fmt.Println(b) // [6 7 8 9 777]
fmt.Println(len(b)) // 5
fmt.Println(cap(b)) // 5
fmt.Println(a) // [1 ... 6 7 8 9 777]
// 再添加一个,容量超长,不会影响原来的数组了
b =append(b,777)
fmt.Println(b) // [6 7 8 9 777 666]
fmt.Println(len(b)) // 6
fmt.Println(cap(b)) // 10
fmt.Println(a) // [1 ... 6 7 8 9 777]
重要概念,容量超长,新建一个切片,容量翻倍,此后对切片数组的操作,不会互相影响
6. 切片的函数传递
引用类型,传递,修改
func main(){
var a []int=make([]int,4,5)
fmt.Println(a) //[0 0 0 0 ]
test(a)
fmt.Println(a) // [999 0 0 0]
}
func test(a []int){
a[0] = 999
fmt.Println(a) // [999 0 0 0]
}
7.多维切片
var a [][]int = make([][]int,3,4)
fmt.Println(a[0]) // []
// 类似数组初始化的 切片初始化
var b []int = []int{1,2,3,4,5}
fmt.Println(b) // [1,2,3,4,5]
fmt.Println(len(b)) // 5
fmt.Println(cap(b)) // 5
// 多维数组的初始化
var a [][]int = []int{{1,2,3,4,5},{2,3},{1,3,4,68,5}}
8. 切片的copy
var a []int=make([]int,4,5)
var b []int = []int{1,2,3,4,5}
fmt.Println(a) // [0 0 0 0]
fmt.Println(b) // [1 2 3 4 5]
// 把b数据copy到a上
copy(a,b)
fmt.Println(a) // [1 2 3 4]
fmt.Println(b) // [1 2 3 4 5]
9. 循环切片
var b []int = []int{1,2,3,4,5}
for _,v:=range b{
fmt.Println(v)
}
/*
1
2
3
4
5
*/
4. map
哈希,键值对
map在定义时,key(数字和字符串)与values的类型固定了
1. 创建map
map的类型
map[key的类型]valuse的类型
var a map[int]string
fmt.Println(a)
// 空值就是nil 引用类型的空值都是nil
定义并初始化(make完成)
var a map[int]string=make(map[int]string)
fmt.Println(a)
定义并初始化,直接赋值
var a map[int]string = map[int]string{1:"v1",2:"v2",3:"v3"}
fmt.Println(a) // map[1:v1 2:v2 3:v3]
2. 添加元素
有就是更新,没有就是添加
//var a map[int]string // 不能往里添加元素
a :=make(map[int]string )
a[1] = "jack" // 添加元素
a[1] = "cheng" // 更新了1
fmt.Println(a)
3.获取元素
//b:= a[9]
b,ok := a[9]
//b,ok := a[1] // 里面有的就是true
println(b) //
println(ok) // false
4.删除元素
//删除元素
var a map[int]string = map[int]string{1:"lqz",2:"egon",3:"Jason"}
fmt.Println(a)
//根据key删除值
delete(a,1)
fmt.Println(a)
5.长度
var a map[int]string = map[int]string{1:"lqz",2:"egon",3:"Jason"}
a[9] = "999"
fmt.Println(len(a))
6. 引用类型
func main(){
var a map[int]string = map[int]string{1:"lqz",2:"egon",3:"Jason"}
fmt.Println(a)
test(a)
fmt.Println(a)
}
func test (map[int]string){
a[1] "9999"
}
7. map的相等性
var a map[int]string = map[int]string{1:"lqz",2:"egon",3:"Jason"}
var b map[int]string = map[int]string{1:"lqz",2:"egon",3:"Jason"}
if a==b{ //map不能通过等号来判断,自己写循环,一个个取判断
}
8. map的value值可以是任意类型
var a map[int]map[string]string = make(map[int]map[string]string)
fmt.Println(a) //a不是nil 是空
fmt.Println(a[1]) // nil 也是空
a[1] = make(map[string]string)
a[1]["1"] = "可以赋值"
//a[1] = map[string]string{"1":"可以赋值"}
fmt.Println(a) //map[1:map[1:可以赋值]]
9. 循环map
var a = make(map[int]string)
a[1]="xxx"
a[2]="x12"
a[3]="x234"
a[4]="xx34"
a[5]="x456"
a[6]="x78"
//map是无序的,python3.6以后就是有序的
for k,v :=range a{
fmt.Println(k)
fmt.Println(v)
}
作业
go中map做成有序
熟悉go语言: 闭包,函数,可变长,切片底层原理,map