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
原文地址:https://www.cnblogs.com/fwzzz/p/12734534.html