15 10 2021

第五章、Go派生/复杂数据类型

        1、指针类型

            1.1 基本介绍

                a、对于基本类型来说,变量存的就是值,也叫值类型,基本数据类型在内存中的布局如下:

                图片.png

                b、获取变量的地址,使用&符号。比如,var i int = 10,获取i的地址:&i

                c、指针类型,指针变量存的是一个地址,这个地址指向的空间才是存的值;比如:var ptr *int = &num     在这里,带了* ptr是一个指针,没带*,ptr是整数。举例:指针在内存的布局

                图片.png

                d、获取指针类型所指向的值,使用 *,比如:var ptr *int ,使用*ptr获取ptr指向的值

                图片.png

            1.2 案例演示

                1.2.1 写一个程序,获取一个int变量num的地址,并显示在终端

                图片.png

                1.2.2 将num的地址赋值给指针ptr,并通过ptr去修改num的值

                图片.png

            1.3 指针细节说明

                a、值类型,都有对应的指针类型,形式为 *数据类型,比如int对应的指针类型就是 *int;*float32对应的指针类型就是 *float32;按此类推

                b、值类型包括:基本数据类型int系列、float系列、bool、string、数组和结构体struct

        2、值类型和引用类型

            2.1 常见的值类型和引用类型

                值类型:基本数据类型int系列、float系列、bool、string、数组和结构体struct

                引用类型:指针、slice切片、map、管道chan、接口interface等都是引用类型

            2.2 值类型和引用类型使用特点

                值类型:变量直接存储,内存通常在栈中(一般生命周期短的分配在栈区,但不绝对是,变量在别的函数用到,有可能放堆区,逃逸了)分配

                图片.png

                引用类型:变量存储的是一个地址,这个地址对应的空间才是真正存储的数据(值),内存通常在堆(一般生命周期长的分配在堆区,但不绝对是)上分配,当没有任何变量引用这个地址时,该地址对应的数据空间就成为一个垃圾,由GC来回收

                图片.png

                内存栈区和堆区示意图:

                图片.png


        3、数组

            3.1 基本介绍

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

            3.2 数组定义和访问数组元素

                方式一、

                var 数组名 [数组长度]数据类型

                var chicken [5]float64

                赋值:chicken[0] = 10  chicken[1] = 20

                方式二、

                变量名 := [数组长度]数据类型{元素值1,元素值2,...} 

                a := [3]int{10,20,30}

                其他方式::

                var chicken [3]int = [3]int{10,20,30}

                var chicken  = [3]int{10,20,30}

                var chicken  = [...]int{5,6,7}

                指定元素值对应下标

                var name = [3]string{1:"tom",2:"LeSeein",3:"yasuo"}

                image.png

                访问数组中元素:chicken[0]     chicken[2]  

                

            3.3 数组在内存的布局

                image.png

                说明:

                a、数组地址可以使用&  取地址获得

                b、数组的第一个元素的地址就是数组的首地址

                c、数组的各个元素的地址间隔是依据数据的类型决定的,比如int 64位系统占用8个字节

                案例演示:

                image.png

            3.4 数组遍历

                方式一:for循环遍历

                image.png

                方式二:for - range方式遍历

                image.png

                案例:

                image.png

            3.5 数组使用细节和注意事项

                a、数组是多个相同类型数据组合,一个数组一旦声明/定义了,其长度是固定的,不能动态变化

                image.png

                b、var  arr []int ,这时候arr是一个slice切片

                c、数组中的元素可以试任何数据类型,包括值类型和引用类型,但是不能混合使用

                d、数组在创建后没有赋值是有默认值的(零值),数值类型默认0 , 字符串类型默认空字符串,bool数组默认false

                image.png

                e、使用数组的步骤: 1.声明数组并开辟空间   2.给各个元素赋值  3.使用数组

                f、数组的下标是从0开始的

                g、数组下标必须在指定范围内使用,否则报panic:数组元素超出长度,比如var arr [3]int,则有效下标为[0-2]

                h、在Go中,数组属于值类型,在默认情况下是值传递,因此会进行值拷贝,数组间不会互相影响

                主函数:

                image.png

                test函数:

                image.png

                数组值拷贝内存详解:

                image.png

                i、如果在其他函数中想修改原来数组的值,可以使用引用传递(指针方式)

                image.png

                image.png                

                函数中修改数组值内存详解:

                image.png

                j、长度是数组类型的一部分,在传递函数参数时,需要考虑数组的长度

                image.png

            3.6 数组应用案例

                image.png

            3.7 多维数组

                3.7.1 二维数组介绍(这里只介绍二维数组)

                3.7.2 二维数组声明、赋值

                image.png

                image.png

                image.png

                image.png


                3.7.3 二维数组应用

                image.png

                3.7.4 二维数组在内存的形式

                image.png

        4、切片

            4.1 在go中为什么需要切片?

            假如我们需要一个数组来保存学生成绩,但是学生人数不确定的情况又该怎么办呢?  解决方案:使用切片!!! 

            4.2 切片的基本介绍

            a、切片的英文是slice

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

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

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

            e、切片定义的基本语法

                var 切片变量名 []类型,比如:var num []int           

            image.png

            4.3 切片在内存中的形式

            image.png

            4.4 切片的使用

            方式一、定义一个切片,然后让切片去引用一个已经创建好的数组,

            image.png

            方式二、通过make来创建切片,基本语法:var 切片名 []type = make([],len,cap)

            说明:type:数据类型   len:大小      cap:指定切片容量,可选,如果分配了cap,则要求cap >= len

            image.png

            

            image.png

            内存布局:

            image.png

            以上两种方式轻易切片的区别:

            a、通过make方式创建的切片可以指定切片的大小和容量

            b、如果没有给切片的各个元素赋值,那么就会使用默认值[int、float=>0  string=>""   bool=>false]

            c、通过make方式创建的切片对应的数组是由make底层维护,对外不可见,即只能通过slice去访问各个元素


            方式三、定义一个切片,直接指定具体数组,使用原理类似make的方式

            image.png

            4.5 以上前两种方式的区别

            a、方式一时直接引用数组,这个数组是事先存在的,程序员是可见的

            b、方式二是通过make来创建切片,make也会创建一个数组,是由切片在底层进行维护,程序员是看不见的,make创建的切片示意图如下:

            image.png

            4.6 切片的遍历

            for循环遍历和for-range遍历

            image.png

            4.7 切片注意事项和细节说明

            a、切片初始化时,var slice = abc[startIndex : endIndex] ,从数组abc下标为 startIndex 开始, 取值到下标为endIndex元素,但不包括endIndex元素

            b、切片引用数组时,不能超过最大长度,范围在0~len(abc)之间,但是可以动态增加

                var slice = abc[0 : endIndex]  可以简写   var slice = abc[ :endIndex]

                var slice = abc[startIndex  : len(abc)]  可以简写   var slice = abc[ startIndex : ]

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

                image.png

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

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

            e、切片可以继续切片

                image.png

                image.png

            e、append()内置函数可以对切片进行动态追加

                image.png

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

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

                2、go底层会创建一个新的数组newArr(安装扩容后的大小,再重新赋值给新的切片)

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

                4、slice重新引用到newArr

                5、newArr是在底层来维护,程序员是看不见的

                image.png

                image.png

                image.png

            f、切片的拷贝操作,使用copy内置函数实现拷贝

                image.png

                说明:

                1、copy(param1,param2)参数类型必须都是切片

                2、param1,param2 两个切片空间独立,互不影响

            g、元素多的切片拷贝给元素少的切片,一样没问题

                image.png

            4.7 string和slice的使用

                4.7.1 string底层是一个byte数组,因此string也可以进行切片处理

                image.png

                4.7.2 string和切片在内存的形式示意图

                image.png

                4.7.3 string是不可变的,也就是说不能通过str[0] = ‘q’方式来修改字符串

                4.7.4 如果要修改string字符串中某一个字符的值,可以转切片修改,修改以后再转string

                image.png

            4.7 切片练习

                image.png


        5、排序和查找

            5.1 排序基本介绍

                排序是指将一组数据,依照指定的顺序进行排列的过程

                第一类:内部排序(数据量比较小)

                将需要处理的所有数据都加载到内部存储器中进行排序,包括(交换式排序法、选择式排序法和插入式排序法)

                image.png

                案例:

                image.png

                第二轮的第一次比较基于第一轮最后一次比较的结果之上进行,以后每次比较同理...

                image.png

                代码:

                image.png                


                第二类:外部排序(数据量比较大)

                数据量过大,无法全部加载到内存中,需要借助外部存储进行排序,包括(合并排序法和直接合并排序法)

            5.1 查找基本介绍

                image.png

                5.1.1 顺序查找

                image.png

                5.1.2 二分查找(前提:有序数列!!!)

                思路分析:

                image.png

                每次折半查找

                image.png

                案例演示:

                image.png

        6、map

            6.1 基本介绍

            map是key-value的数据结构,又称为字段或者关联数组,官方称之为映射,类似其他编程语言的集合

            6.2 基本语法

            var map 变量名     map[keytype]valuetype

            keytype可以是什么类型::golang中map,key的类型又很多,比如:bool,数字,string,指针,channel,还可以是只包含前面几个类型的接口、结构体、数组, 通常为有int、string

            注意:slice、map还有function不可以,因为这几个没法用==来判断

            valuetype可以是什么类型::基本跟keytype一样的,通常为数字(整数、浮点数)、字符串、map、struct

            

            image.png

            注意:map跟数组不一样,数组声明以后就已经分配内存空间地址了

            6.3 案例演示

            image.png   

            说明:

            map在使用前一定要先make;map的key不能重复,重复了就是最后一个key-value值;map的value值可以试相同的;map的key-value是无序的

            6.4 map的使用方式

             image.png

            案例:

            image.png

            6.5 map的增删改查操作

            a、添加和更新

            image.png

            b、删除

            image.png

            注意:如果我们要删除map的所有key,没有一个专门的方法一次删除,可以遍历一下key,逐个删除,或者map = make(...),make一个新的,让原来的称为垃圾,被gc回收

            image.png

            c、查询

            查询有两个返回参数   var,findRes = names["num1"]  var就是查找的key对应的value值,findRes查找结果(值为true 和 false)

            image.png

            image.png

            image.png

            6.6 map遍历,只能使用for-range结构遍历,map的key不一定都是数字

            image.png

            6.7 map的长度统计,使用len函数

            image.png

            image.png

            6.8 map切片

            基本介绍:

            切片的数据类型如果是map,则我们称之为slice of map,map切片,这样使用则map这个数就可以动态变化了

            image.png

            6.9 map排序

            基本介绍:

            a、golang中没有专门的方法针对map的key进行排序

            b、golang中map默认是无序的,注意,也不是按照添加的顺序存放的,你每次遍历,得到的输出可能不一样

            c、golang中map的排序,是先将key排序,然后根据key值遍历输出即可

            image.png

            6.10 map使用细节说明

            a、map是引用类型,遵守引用类型传递机制,在一个函数接收map,修改后,会直接修改原来的值

            b、map容量达到后,再想map增加元素,会自动扩容,并不会发生panic,也就是说,map能动态的增加键值对

            c、map的value也经常使用struct类型,更适合管理一些复杂数据类型

            案例演示:

            image.png

            image.png

        7、管道channel

            7.1 基本介绍

            image.png

            image.png

            7.2 管道示意:

            image.png

            image.png

            image.png

            7.3 管道基本使用

            声明/定义channel:

            var 变量名  chan 数据类型   !!!


            var perChan chan *Person

            var intChan  chan int

            var mapChan chan map[int]string    (用于存放map[int]string类型数据)

            说明:

            1.channel是引用类型

            2.channel必须初始化才能写入数据,即make后才能使用

            3.channel是有类型的,intChan 只能写入int类型数据

            

            演示管道的使用:

            image.png

            image.png

            7.4 channel使用注意事项

            a、channel中只能存放指定的数据类型

            b、channel中数据放满了就不能再往里面存放数据了

            c、如果从channel中取出数据以后就可以继续存放

            d、在没有使用协程的情况下,如果channel数据取完了,再取,就会报dead lock


            7.5读写channel案例演示

            image.png

            image.png

            7.6 channel的遍历和关闭

            image.png

            image.png