美文网首页
10-Go语言数组和切片

10-Go语言数组和切片

作者: 喝酸奶要舔盖__ | 来源:发表于2018-09-23 12:33 被阅读0次

    Go语言数组数组

    一维数组
    • 数组定义格式: var arr [3]int
    • 数组的初始化方式
      • 先定义后初始化
        注意点:Go语言数组支持先定义后一次性初始化
      //1.先定义后初始化
            var nums [3]int
            //先定义数组再逐个初始化
            nums[0] = 1
            nums[1] = 2
            nums[2] = 3
      
            //先定义数组再一次性初始化
            nums = [3]int{2,3,4}
            fmt.Println(nums)
      
      • 定义的同时初始化
        • 注意点:给数组一次性赋值的时候一定要在值的前面加上数组的类型,而且必须要和数据类型一模一样
        • C语言中数组没有初始化保存的是垃圾数据,Go语言中数组没有初始化保存的是零值
      //var arr [3]int = [3]int{2, 3, 4}
        //定义的同时部分初始化,未初始话的元素为0
        var arr [3]int = [3]int{1,3}
        //指定元素初始化
        var arr [3]int = [3]int{2:4}
        //[...]的含义, 让编译器根据赋值的元素个数自动计算数组的元素个数
        arr := [...]int{1,3,4}
        fmt.Println(arr)
        fmt.Println(arr[0])
        fmt.Println(arr[1])
        fmt.Println(arr[2])
      

    零值
    • 什么是零值
      • 数据类型未初始化,系统自动添加的数据
      • 各种数据类型零值
        • int/int8/int16/int32/int64/uint/uint8/uint16/uint32/uint64/byte/rune/uintptr的默认值是0
        • float32/float64的默认值是0.0
        • bool的默认值是false
        • string的默认值是""
        • pointer/function/interface/slice/channel/map/error的默认值是nil

    值类型
    • Go语言在数组中是值类型,所以数组之间的赋值是值拷贝关系,而不是指向关系
    • 如果想让两个数组可以相互赋值, 那么两个数组的类型必须一致类型一致包括元素个数, 元素个数也是Go语言中数组类型的一部分
    • 如果数组中存储的元素类型支持== != 操作,而且两个数组的类型是一个样的, 那么数组也支持== !=操作
    package main
    
    import "fmt"
    
    func main() {
        nums := [...]int {2,3,4}
        arr := [...]int{2,3,4}
        fmt.Println(nums == arr) //true
    
        nums := [3]int{1,2,3}
        res := nums
        fmt.Println(res) //[1,2,3]
    
        nums := [3]int{1,2,3}
        change(nums)
        fmt.Println(nums)  //[1,2,3]
    
    }
    //函数内部无法改变数组元素的值
    func change(nums [3]int)  {
        nums[2] = 666
    }
    

    二维数组
    • Go语言二维数组格式: var 数组名称[一维数组个数][一维数组元素个数]数组类型
    package main
    
    func main() {
        //定义二维数组格式
        var nums [2][3]int = [2][3]int{
            {1,3,5},
            {2,5,6},
        }
    
        //简单定义方法
        nums := [2][3]int{
            {1,2,3},
            {4,5,6},
        }
    
        arr := [...][3]int{
            {12,3,5},
            {1,2,6},
        }
        fmt.Println(arr)
       //二维数组也可以省略元素个数,但是只可以省略行数,不可以省略列数
        arr := [...][3]int{
            {12,3,5},
            {1,2,6},
        }
    
        //遍历二维数组
        for i:=0; i< 2; i++{
            for j:=0;j < 3 ;j++  {
                fmt.Println(arr[i][j])
            }
        }
    }
    

    数组的遍历
    • Go语言数组遍历两种方法
      • 普通for循环遍历
      nums := [...]int{2, 3, 5, 1, 3, 6}
        //普通for循环遍历
        for i := 0; i < 6; i++ {
            fmt.Println("index= ", i, "value = ", nums[i])
        }
      
      • for..range遍历
      nums := [...]int{2, 3, 5, 1, 3, 6}
        //高级for循环遍历
        for key,value := range nums{
            fmt.Println(key,"-->",value)
        }
      

    Go语言切片

    切片
    • 什么是切片

      • 在Go语言中,数组的长度一旦确定就无法改变,为了解决这一问题,推出了一种数据类型切片
      • 切片简单理解就是一个可变长度的数组,底层的实现原理就是一个结构体, 结构体中有一个指针指向了一个数组
        本质上所有的数据都是保存在指向的数组中的
    • 创建切片

      • 通过数组创建切片1
        通过数组来创建
        格式: [起始位置:结束位置], 从起始位置开始截取, 直到结束位置, 但是不包括结束位置
        注意:  截取了多少个元素, len就等于几
               容量等于数组的长度 - 起始位置
        nums := [5]int{1,2,3,4,5}
        //1.通过数组创建切片
        //1.1[起始位置 : 结束位置] 从起始位置开始截取,直到结束位置,但是不包括结束位置索引对应的元素
        var sce []int = nums[2 : 4]
      
        //1.2[: 结束位置]只指定结束位置,不指定起始位置,就是从开始位置截取直到指定的位置,但是也不包括指定位置的元素
        var sce []int = nums[:3]
      
        //1.3[起始位置 : ] 从起始位置开始截取,直到末尾
        var sce []int = nums[0:]
      
        //1.4[: ]只有一个:,从开始位置截取,直到末尾结束
        var sce []int = nums[:]
        fmt.Println(sce)
        //计算切片的长度len当前保存的数据个数
        fmt.Println(len(sce))
        //计算切片的容量cap总共能够保存数据的个数
        fmt.Println(cap(sce))
      
      
      • 通过数组创建切片2
        切片的第三个参数max,不能小于第二个参数,作用是用来控制切片容量的
        //如果指定了第三个参数, 那么切片的容量就等于 第三个参数 - 第一个参数
        //注意点: 如果没有指定第三个参数,那么切片的容量 = 数组的容量 - 第一个参数值
        //        如果指定了第三个参数,那么切片的容量 = 第三个参数 - 第一个参数值
        arr := [7]int{1,2,3,4,5,6,7}
        sce := arr[1:4:4]
        fmt.Println(sce)
        fmt.Println(len(sce))
        fmt.Println(cap(sce))
      
      • 通过make()函数创建切片
       // 2.通过make函数创建切片
        // 第一个参数: 告诉系统要存储什么类型的数据
        // 注意点: 如果是创建切片一定要在传入的数据类型前面写上[]
        // 第二个参数: 告诉系统创建出来的切片len等于多少
        // 第三个参数: 告诉系统创建出来的切片cap等于多少
        // 注意点: 第三个参数可以省略, 如果省略切片的容量就等于切片的长度(等于第二个参数)
        //var sce []int = make([]int, 2, 5)
        var sce []int = make([]int, 2)
        fmt.Println(sce)
        fmt.Println(len(sce))
        fmt.Println(cap(sce))
      
      • 通过语法糖创建切片
        // 3.通过Go提供的语法糖来创建
        // 一定要注意[]里面没有值就是切片
        // 通过Go提供的语法糖来创建len等于cap
        var sce []int = []int{1, 3, 5} // 相当于make([]int, 3)
        fmt.Println(sce)
        fmt.Println(len(sce))
        fmt.Println(cap(sce))
      

    切片与数组
    • [ ]没有数字就是切片,有数字就是数组,[...]这种定义格式是数组
      //定义数组
        var arr [5]int = [5]int{1,3,4,5,6}
        var arr = [5]int{1,3,4,5,6}
        arr := [5]int{1,3,4,5,6}
        arr := [...]int{1,3,4,5,6}
    
    //定义二维数组
        var arrs [2][3]int = [2][3]int{
            {1,3,5},
            {2,4,6},
        }
        var arrs = [2][3]int{
            {1,3,5},
            {2,4,6},
        }
    
        arrs := [2][3]int{
            {1,3,5},
            {2,4,6},
        }
    
        arrs := [...][3]int{
            {1,3,5},
            {2,4,6},
        }
    
      //定义切片
        var sce []int = []int{1,3,5}
        var sce = []int{1,3,5}
        sce := []int{1,3,5}
    
    //定义一个切片,切片中保存的是数组
        var sec [][3]int = [][3]int{
            {1, 3, 5},
            {2, 4, 6},
        }
    
        var sec = [][3]int{
            {1, 3, 5},
            {2, 4, 6},
        }
    
        sec := [][3]int{
            {1, 3, 5},
            {2, 4, 6},
        }
    
    //定义一个切片,切片中保存切片
        var sec[][]int = [][]int {
            {1, 3, 5},
            {2, 4, 6},
        }
    
        var sec = [][]int {
            {1, 3, 5},
            {2, 4, 6},
        }
        sec := [][]int {
            {1, 3, 5},
            {2, 4, 6},
        }
    

    append函数
    • append函数格式 :append(切片,数据)
    • append函数作用: 追加切片中的数据
    • append函数注意点
      • 如果通过append函数追加数据之后超过了原有的容量, 那么系统内部会自动按照当前容量*2的方式重新定义一个数组作为切片保存数据的模型
      • 在扩容的时候会重新定义一个新的切片, 所以需要返回一个切片
      • 扩容问题
        • 容量小于1024的时候扩容, 会按照原有容量的2倍扩容
        • 容量大于1024的时候扩容,会按照原有的1/4进行扩容
        sec := make([]int, 1024, 1024)
        sec = append(sec, 6)
        fmt.Println(len(sec))
        fmt.Println(cap(sec))//1280
    

    切片的使用
    • 定义切片
    sec := []int{1,3,5,7,9,11}
    
    • 修改切片中的数据
    sec[2] = 666
    
    • 增加切片中的数据
    sec = append(sec, 7)
    fmt.Println(sec)
    
    • 删除切片中指定的数据
    //5.删除切片中的指定索引对应的数据
        index := 3
        //不仅可以利用数组获取切片,还可以用切片获取切片
        //sec = sec[:index]
        //fmt.Println(sec) //[1 3 5]
        //sec = sec[index +1 :]
        //fmt.Println(sec) //[9 11]
        //将第二个切片追加到第一个切片后面即可
        sec = append(sec[:index], sec[index +1 :]...)
        fmt.Println(sec) //[1 3 5 9 11]
    

    切片的内存地址
    package main
    
    import "fmt"
    
    func main() {
        /*
        通过切片生成切片的注意点
        */
    
        //1.创建一个数组
        var arr  = [3]int{1,2,3}
        //Go语言中不能通过数组名称获取数组的地址
        //fmt.Printf("%p\n", arr)
        fmt.Printf("%p\n", &arr) //0xc0420500a0
        fmt.Printf("%p\n", &arr[0]) //0xc0420500a0
    
        //2.通过数组创建一个切片
        //直接打印sce打印的是sce中指针保存的地址,也就是底层指向的那个数组的地址
        sce := arr[:]
        fmt.Printf("%p\n", sce) //0xc0420500a0
    
        //3.通过切片创建切片
        //通过切片创建一个切片, 新的切片和老的切片底层指向同一个数组
        sce2 := sce[:]
        fmt.Printf("%p\n", sce2) //0xc0420500a0
    
        //修改数组中的值
        arr[2] = 666
        sce[2] = 666
        sce2[2] = 666
        fmt.Println(arr)
        fmt.Println(sce)
        fmt.Println(sce2)
    }
    
    copy函数
    package main
    
    import "fmt"
    
    func main() {
        /*
        copy函数的作用是将源切片的值拷贝到目标切片当中
        函数格式 copy(目标切片, 源切片)
    
         */
        sec1 := []int{1, 2, 3, 6, 9, 10}
        sec2 := make([]int, 2, 5)
        fmt.Println(sec2)
        //将源切片的值拷贝到目标切片当中
        //注意点: 拷贝的时候是以目标切片为准,目标切片中长度为多少将来只能拷贝多少个值进来
        copy(sec2, sec1)
        fmt.Println(sec2)
    }
    
    
    切片与字符串

    注意点: 切片和数组不同, 切片不支持== !=操作

    package main
    
    import "fmt"
    
    func main() {
        /*
        1.切片可以再生成新的切片, 两个切片底层指向同一个数组
        2.切片和数组不同, 切片不支持== !=操作
        3.在Go语言中字符串的底层实现就是切片, 所以可以通过字符串来生成切片
        */
    
        //数组可以使用== !=操作
        //arr := [3]int{1,2,3}
        //arr2 := [3]int{4,5,6}
        //arr = arr2
        //fmt.Println(arr)
    
    
        var str string = "www.it666.com"
        sec := make([]byte, len(str))
        copy(sec,str)
        fmt.Println(len(str))
        fmt.Printf("%s\n",sec) //www.it666.com
    }
    
    切片与数组注意点
    • 数组定义后不初始化,可以使用,切片定义后可以一次性初始化,但是不能逐个初始化,但是可以使用append函数添加数据
    • 数组定义后直接使用
    var arr [4]int
        //数组定义后可以直接使用
        arr[0] = 1
        arr[1] = 3
        arr[2] = 5
        arr[3] = 7
    
        fmt.Println(arr)
    
    • 切片定义后不能直接使用
        var sce []int
        //不能逐个初始化,会报错
        //sce[0] = 1
        //sce[1] = 3
        //sce[2] = 5
    
        //可以使用append函数添加数据
        sce = append(sce,1)
        sce = append(sce,3)
        sce = append(sce,5)
        sce = append(sce,7)
        sce = append(sce,9)
    
        //打印切片
        fmt.Println(sce)
        fmt.Println(len(sce))
        fmt.Println(cap(sce))
    
    • 计算数组的长度方式
        //计算数组长度的方式
        //第一种方式(推荐)使用len函数
        arr := [4]int{1,3,5,7}
        //length := len(arr)
        //fmt.Println(length)
    
        //第二种方式,使用unsafe.Sizeof函数计算(不推荐)
        length1 := unsafe.Sizeof(arr)
        length2 := unsafe.Sizeof(arr[0])
        fmt.Println(length1 / length2)
    
    • 计算切片的长度
        //计算切片的长度
        //第一种方式(推荐)使用len函数
        //注意点: 切片的长度不能使用unsafe.Sizeof函数计算
        //由于切片本质是结构体,所以unsafe.Sizeof计算的是结构体的字节数,不是指向数组的字节数
        sce := []int{1,3,5,6}
        length := len(sce)
        fmt.Println(length)
    
    • 切片与数组的传递
      • 数组传递是值传递
      • 切片传递是地址(指针)传递
    package main
    
    import "fmt"
    
    func main() {
        /*
        1.数组作为函数参数是值传递,在函数内部修改形参是不会影响外部实参的值
        2.切片作为函数的参数是地址传递(指针), 在函数内修改形参, 会影响到函数外的实参
        */
        //arr := [4]int{1,3,4,5}
        //fmt.Println(arr)
        //change1(arr)
        //fmt.Println(arr)
    
        sce := []int{1,2,3,4}
        fmt.Println(sce)
        change2(sce)
        fmt.Println(sce)
        
    }
    //数组是值传递
    func change1(arr [4]int)  {
    arr[0] = 666
    }
    
    //切片是地址传递指针
    func change2(sce []int)  {
        sce[0] = 666
    }
    
    

    可变参数

    • 可变参数底层实现就是切片
    package main
    
    import "fmt"
    
    func main() {
        /*
        可变参数,底层其实就是一个切片
        */
        res := sum(10,20,30)
        fmt.Println(res)
    
    }
    //可变参数底层就是一个切片
    //注意点: 当一个函数中定义可变参数时候,可变参数只能放在形参列表的最后面
    func sum(nums ...int) (res int) {
        for _, value := range nums {
            res += value
        }
        return
    }
    

    相关文章

      网友评论

          本文标题:10-Go语言数组和切片

          本文链接:https://www.haomeiwen.com/subject/sowfoftx.html