go_切片

切片

复制代码
# 定义
切片是由数组建立的一种方便、灵活且功能强大的包装(Wrapper)。切片本身不拥有任何数据。它们只是对现有数组的引用
数组定长,长度不能改变---》python中列表----》go切片


# 知识点
1 创建一个切片(通过数组创建)
    
2 使用 make 创建一个切片    
3 切片的修改
4 切片的长度和容量

5 追加切片元素
6 切片的函数传递
7 多维切片
8 内存优化
——————————————————————————————————
package main

import "fmt"

// 切片

func main() {
    // 1 创建一个切片(通过数组创建)
    var a [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    // 切片--->从a数组上,从0到结尾,切片赋值给s
    //var s = a[:]
    var s []int = a[:]
    fmt.Println(s)
    // 查看类型--->中括号中没有数字-->就是切片,有数字就是数组
    // 区分数组(值)和切片(引用)类型
    fmt.Printf("s的类型是:%T\n", s) // []int

    // 2 使用 make 创建一个切片-->必须通过make或通过数组切出来,否则是空的
    var s1 []string = make([]string, 4)
    fmt.Println(s1)

    // 3 切片零值
    // 3.1 通过数组切出来,不会为 空
    // 3.2 如果只定义,没有初始化--》零值---》空---》nil
    var s2 []string
    fmt.Println(s2) // []

    // 4 操作切片---》取值,赋值---》使用 [数字]
    s1[0] = "lqz"
    s1[1] = "彭于晏"
    fmt.Println(s1)
    s1[0] = "ssdfasdf"
    fmt.Println(s1)

    // 5 如果切片为  空,nil--》没有初始化 不能使用(取值赋值)

    s2 = make([]string, 1) // 不是nil了,但是长度为0
    if s2 == nil {         // python 的None
        fmt.Println("s2不能初始化,不能使用")
        return
    }
    s2[0] = "lqz" // s2没有初始化,报错  index out of range [0] with length 0
    fmt.Println(s2)

    // 使用切片 s1[0]---》报index out of range [0] with length 0--》两个原因:1 nil 2 长度不够

    // 6 切片的长度和容量
    // 长度:切片放了几个值
    // 容量:切片总共能放几个值
    var a1 [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    var s3 []int = a1[2:3]
    fmt.Println(s3)      // [6 7]  前闭后开区间
    fmt.Println(len(s3)) // len 长度 2
    fmt.Println(cap(s3)) // cap 容量 5 切片基于底层数组,容量取决于底层数组--》从切片起始位置到数组最后

    var s4 = make([]int, 2, 4)
    fmt.Println(len(s4)) // 2
    fmt.Println(cap(s4)) // 4

    // 7 追加切片元素
    // s4 长度是2,容量是4,还能追加俩值
    s4 = append(s4, 99) // 内置函数追加--->s4不是对象
    fmt.Println(s4)
    fmt.Println(len(s4)) // 3
    fmt.Println(cap(s4)) // 4
    s4 = append(s4, 88)  // 内置函数追加--->s4不是对象
    fmt.Println(s4)
    fmt.Println(len(s4)) // 4
    fmt.Println(cap(s4)) // 4
    // 超过容量,再追加---》不会报错---》
    s4 = append(s4, 77) // 内置函数追加--->s4不是对象
    fmt.Println(s4)
    fmt.Println(len(s4)) // 5
    fmt.Println(cap(s4)) // 8---》翻倍扩容

    s4 = append(s4, 66, 55, 44, 33) //
    fmt.Println(s4)
    fmt.Println(len(s4)) // 9
    fmt.Println(cap(s4)) // 16---》翻倍扩容

    s4 = append(s4, 22, 11, 12, 13, 11, 12) //
    fmt.Println(s4)
    fmt.Println(len(s4)) // 16
    fmt.Println(cap(s4)) // 16---》翻倍扩容-->32

    //8 切片的函数传递  切片是引用类型
    test001(s4)            // [0 0 99 88 77 66 55 44 33 22 11 12 13 11 12 13]
    fmt.Println("外部:", s4) // 函数内修改,会影响原来的值

    // 很深的坑: s4 长度和容量 都是16 当参数传到函数中,修改,会不会影响原来的?
    test002(s4)
    fmt.Println("外部:", s4) // 函数内修改,会影响原来的值
    /*
        1 因为切片依赖于底层数组
        2 底层数组的改变会影响切片,切片的改变也会影响底层数组
        3 当使用append追加上,如果超过了切片容量--》切片会扩容--》重新创建一个数组--》把原来的值复制过去--》容量翻倍了--》切片指向新的数组
        4 如果当参数传递,再函数中,使用append
            1 超过容量,只要超过后,再修改某个位置的值,就不会相互影响了
            2 如果没有超过容量,再修改某个位置的值,会相互影响了
    */

    // 9 多维切片
    var s5 [][]int = make([][]int, 2, 3)
    //s5[0]=1
    s5[0] = make([]int, 3) // 内层切片使用,也要初始化
    s5[0][0] = 99          // 报错了---》内层的切片,没有通过make初始化出来,不能用
    fmt.Println(s5)

    var s6 [][3]int = make([][3]int, 2, 3)
    fmt.Println(s6[0])
    s6[0][0] = 99
    fmt.Println(s6)

    // 多维切片,第n层,要不要初始化,取决于第n层是什么类型

    // 定义并赋初值
    var s7 [][]string = [][]string{{"lqz", "小红"}, {"asfd"}, {"111", "22", "333", "444"}}
    //var s7 [][4]string = [][4]string{{"lqz", "小红"}, {"asfd"}, {"111", "22", "333", "444"}}
    fmt.Println(s7[0][1])
    fmt.Println(len(s7[2])) // 1
    fmt.Println(cap(s7[2])) // 1
    //fmt.Println(s7[2][4])   // 越界了
    //fmt.Println(s7[0][2]) // 数组不会越界,切片就会越界
    s7[0] = append(s7[0], "")
    fmt.Println(len(s7[0])) // 3
    fmt.Println(cap(s7[0])) // 4

    // 10 内存优化  copy函数
    var a3 [100]int
    fmt.Println(a3)
    var s8 []int = a3[0:3]
    fmt.Println(s8)
    s8[0] = 88
    fmt.Println(s8)
    fmt.Println(a3)
    a3[1] = 66
    fmt.Println(s8)
    fmt.Println(a3)

    //s8 拷贝到小一点的切片上(底层数组小)  ---》可以大可以小
    var s9 = make([]int, 5, 5)
    copy(s9, s8)
    fmt.Println(s9) // 长度和容量,都是3--》以后操作s9-->传参,修改---》底层数组只有3的大小---》内存空间占用小

}

func test001(s []int) {
    s[0] = 999
    fmt.Println(s)
}

func test002(s []int) {
    s[0] = 999
    fmt.Println(s)
    // 如果,再内部,append--——》追加--》超过容量--》放弃掉底层数组---》新创建一个新数组--》指向新数组
    s = append(s, 666)
    fmt.Println("内部", s)
    s[0] = 888
    fmt.Println("内部", s)

}
复制代码

可变长参数

复制代码
package main

import "fmt"

// 可变长参数
func main() {
    // *  ** 放在形参上
    // *:接收任意长度的位置参数
    // ** 接收任意长度的关键字参数

    // * ** 放在实参上--》* 只能放在列表上,  ** 只能放在字典上

    // go 只有按位置传参数---》没有按关键字这种用法
    test003(33, 44, "9")

    // 传任意长度参数
    //fmt.Println(1,2,3,4,5,"dafas")

    test004("11", "22", "14", "15", "16", "17", "18", "19")

    var ss1 [5]string = [5]string{"lqz", "彭于晏", "刘亦菲"}
    test004(ss1[:]...) // 打散了传入

    // 思考题
    welcome := []string{"hello", "world"} // 长度是2,容量是2
    //welcome := make([]string,3,4) //
    change(welcome...)   // 内部本质就是把 welcome 给了 s
    fmt.Println(welcome) // {"Go", "world"}
}

func test003(a, b int, c string) {
    fmt.Println(a, b, c)
}

func test004(a ...string) {
    fmt.Println(a) // 可以传任意长度字符串===>a是什么类型?字符串类型? 字符串切片类型 []string
    fmt.Printf("a的类型是:%T", a)
    //for i := 0; i < len(a); i++ {
    //    fmt.Println(a[i])
    //}

    for _, value := range a {
        fmt.Println(value)

    }
}

func change(s ...string) {
    s[0] = "Go"
    s = append(s, "playground")
    fmt.Println(s) // [Go world  playground]
    s[0] = "lqz"
    fmt.Println(s) // [lqz  world  playground]
}
复制代码

map

复制代码
# 数组,切片,map  容器类型

# map 是在 Go 中将值(value)与键(key)关联的内置类型。通过相应的键可以获取到值

如何创建 map
给 map 添加元素
获取 map 中的元素
删除 map 中的元素
获取 map 的长度
Map 是引用类型
Map 的相等性
复制代码

hash冲突

复制代码
# python中的字典 
# go中得map
# redis中得 hash
# java中得 HashMap,TreeMap

# 1  就是根据key即经过一个函数f(key)得到的结果的作为地址去存放当前的key value键值对(这个是hashmap的存值方式),但是却发现算出来的地址上已经有人先来了

就是相当于你在蹲坑,又有人进来了,但是只有一个坑,就产生了冲突,需要开辟新的空间去让另一个人有地方上厕所


# 2 解决hash冲突
    1 开放寻址法
        1.1  线性探测
        按顺序决定值时,如果某数据的值已经存在,则在原来值的基础上往后加一个单位,直至不发生哈希冲突。
        就是在此空间不足时,直接放入此空间的后一个空的空间
        1.2 伪随机探测
            
        
    2 再哈希法(Rehashing):
        使用另一个哈希函数处理冲突
    
    3 链地址法(java的hashmap):
        - 对于相同的值,使用链表进行连接。使用数组存储每一个链表

    4 建立公共溢出区
复制代码

 

posted @   拆尼斯、帕丁顿  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示