• Go复合数据类型(数组、切片、映射)


    数据类型: 序列、映射、集合、树、图

    序列
    有序的数据集
    数组
    切片
    字符串
    相同的特征 => 相同的操作

    数组

    数组是一个由固定长度的特定类型元素组成的序列,数据项叫做数组的元素,一个数组可以由零个或多个元素组成。 因为数组的长度是固定的,数组的长度必须是非负整数的常量,长度也是类型的一部分,所以[5]int和[10]int是属于不同类型的。

    声明

    数组声明需要指定组成元素的类型以及存储元素的数量(长度)。在数组声明后,其长度不可修改,数组的每个元素会根据对应类型的零值对进行初始化

    package main
    
    import "fmt"
    
    func main() {
    	// 定义变量names为元素类型为字符串长度为55的数组
    	var names [55]string // string 55
    	var scores [10]int
    	fmt.Printf("%T, %T
    ", names, scores) //[55]string, [10]int
    	fmt.Printf("%q
    ", names) //["" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""]
    	fmt.Println(scores) //[0 0 0 0 0 0 0 0 0 0]
    }
    

    字面量

    (1)指定数组长度: [length]type{v1, v2, …, vlength}
    
    (2)使用初始化元素数量推到数组长度: […]type{v1, v2, …, vlength}
    
    (3)对指定位置元素进行初始化: [length]type{index:vm, …, start:in}
    
    	var users [2]string = [2]string{"a", "实时"}
    	bounds := [...]int{10, 20, 30, 40, 50}
    	teachers := [2]string{"qq"}
    	nums := [10]int{1:20, 3:50, 8:90, 5:10}
    
    	fmt.Printf("%q
    ", users) //["a" "实时"]
    	fmt.Println(bounds) //[10 20 30 40 50]
    	fmt.Printf("%q
    ", teachers) //["qq" ""]
    	fmt.Println(nums) //[0 20 0 50 0 10 0 0 90 0]
    

    操作

    // 关系运算 != ==
    	var nums [2]int = [...]int{100, 88}
    	var scores = [...]int{100, 88}
    	fmt.Println(nums == scores)
    
    // 访问值 
    	// 索引 ()
    	fmt.Println(nums[0])
    	fmt.Println(nums[1])
    // 修改值
    	nums[0] = 101
    	nums[1] = 102
    	fmt.Println(nums)
    
    // 如何计算数组的长度
    	fmt.Println(len(nums))
    
    //数组的切片操作
    	nums := [...]int{1, 2, 3, 4, 5}
    	// nums2 := nums[1:3]
    	// fmt.Printf("%T
    ", nums2)
    	// fmt.Println(nums2)
    	// //0 <= start <= end <= length
    	// // cap = length - start //容量大小
    	// // len = end - start
    	// fmt.Println(cap(nums2), len(nums2))
    
    	// start end cap_end
    	nums2 := nums[1:3:4]
    	fmt.Println("%T
    ", nums2)
    	fmt.Println(nums2)
    	// 0 <= start <= end <= cap_end <= length
    	// cap = cap_end -start //容量大小
    	// len = end - start
    	fmt.Println(cap(nums2), len(nums2)) // 3 2 
    
    // 遍历
    // 可以通过 for+len+访问方式或 for-range 方式对数组中元素进行遍历
    	for i := 0; i < len(nums); i++ {
    		fmt.Println(i, nums[i])
    	}
    
    	for v := range nums {
    		fmt.Println(v, nums[v]) //v值是索引
    	}
    
    	for i, v := range nums {
    		fmt.Println(i, v) //i索引 v元素值
    	}
    

    多维数组

    数组的元素也可以是数组类型,此时称为多维数组

    声明&初始化
    	//[length]type
    	// type [2]int
    	// 二维数组
    	var ms [3][2]int
    
    	fmt.Printf("%T
    ", ms)
    	fmt.Println(ms)
    
    	fmt.Printf("%T %v
    ", ms[0], ms[0])
    	fmt.Printf("%T %v
    ", ms[0][0], ms[0][0])
    
    	ms = [...][2]int{ //[...]推导,不能推导二维[2]
    		1: [2]int{1, 2},
    		2: [2]int{3, 4},
    		0: [2]int{5, 6},
    	}
    	// [[5, 6], [1, 2], [3, 4]]
    
    访问&修改
    	var ms [3][2]int
    	fmt.Printf("%T %v
    ", ms[0], ms[0])
    	fmt.Printf("%T %v
    ", ms[0][0], ms[0][0])
    	ms = [...][2]int{
    		1: [2]int{1, 2},
    		2: [2]int{3, 4},
    		0: [2]int{5, 6},
    	}
    	// [[5, 6], [1, 2], [3, 4]]
    
    	ms[0][1] = 100
    	fmt.Println(ms)
    
    	ms[1] = [2]int{101, 102}
    	fmt.Println(ms)    
    
    遍历
    	ms := [...][2]int{
    		1: [2]int{1, 2},
    		2: [2]int{3, 4},
    		0: [2]int{5, 6},
    	}
    	for i, line := range ms {
    		fmt.Println(i, line)
    		for j, v := range line {
    			fmt.Println(i, j, v)
    		}
    	}
    

    slice切片

    Slice(切片)代表变长的序列,序列中每个元素都有相同的类型。一个slice类型一般写作 []type,其中type代表slice中元素的类型;slice的语法和数组很像,只是没有固定长度而已。

    数组和slice之间有着紧密的联系。一个slice是一个轻量级的数据结构,提供了访问数组子序 列(或者全部)元素的功能,而且slice的底层确实引用一个数组对象。一个slice由三个部分构成:指针长度容量。指针指向第一个slice元素对应的底层数组元素的地址,要注意的是slice的第一个元素并不一定就是数组的第一个元素。长度对应slice中元素的数目;长度不能超过容量,容量一般是从slice的开始位置到底层数据的结尾位置。内置的len和cap函数分别返回slice的长度和容量。

    指针:指向切片第一个元素指向的数组元素的地址
    长度:切片元素的数量
    容量:切片开始到结束位置元素的数量
    

    多个slice之间可以共享底层的数据,并且引用的数组部分区间可能重叠。下图显示了表示一年中每个月份名字的字符串数组,还有重叠引用了该数组的两个slice。数组这样定义

    months := [...]string{1: "January", /* ... */, 12: "December"}
    

    因此一月份是months[1],十二月份是months[12]。通常,数组的第一个元素从索引0开始,但是月份一般是从1开始的,因此我们声明数组时直接跳过第0个元素,第0个元素会被自动初始化为空字符串。

    声明

    切片声明需要指定组成元素的类型,但不需要指定存储元素的数量(长度)。在切片声明后,会被初始化为 nil,表示暂不存在的切片

    	var names []string
    	fmt.Printf("%T, %t, %v
    ", names, names == nil, names) //[]string, true, []
    

    初始化

    (1)使用字面量初始化:[]type{v1, v2, …, vn}
    (2)使用字面量初始化空切片: []type{}
    (3)指定长度和容量字面量初始化:[]type{im:vm, in:vn, ilength:vlength}
    (4)使用 make 函数初始化
    (5)make([]type, len)/make([]type, len, cap),通过 make 函数创建长度为 len,容量为cap的切片,len必须小于等于cap
    (6)使用数组切片操作初始化:array[start:end]/array[start:end:cap](end<=cap<=len)
    
    	scores := [...]int{60, 68, 70, 80, 86, 61}
    
    	var scores00 []int = []int{80, 90, 67}
    	scores01 := []int{}
    	scores02 := []int{0:80, 2:98}
    	//make([]T, len, cap) // same as make([]T, cap)[:len]
    	scores03 := make([]int, 3)
    	scores04 := make([]int, 3, 5)
    	scores05 := scores[1:3]
    	scores06 := scores[1:3:3]
    
    	fmt.Printf("%T %T %T %T %T %T
    ", scores00, scores01, scores02, scores03, scores04, scores05) //[]int []int []int []int []int []int
    
    	fmt.Println(scores00) //[80 90 67]
    	fmt.Println(scores01) //[]
    	fmt.Println(scores02) //[80 0 98]
    	fmt.Println(scores03) //[0 0 0]
    	fmt.Println(scores04) //[0 0 0]
    	fmt.Println(scores05) //[68 70]
    	fmt.Println(scores06) //[68 70]
    

    操作

    访问和修改元素
    	names := []string{1: "赵昌建", 10: "sen"}
    	fmt.Printf("%T
    ", names)
    	fmt.Printf("%q
    ", names) //["" "赵昌建" "" "" "" "" "" "" "" "" "sen"]
    	// 访问 修改元素
    	// 索引
    	fmt.Println(names[1])
    	fmt.Println(names[10])
    	fmt.Println(names[9])
    	names[9] = "卫智鹏"
    	fmt.Println(names)
    
    获取切片长度和容量

    使用 len 函数可获取切片的长度,使用 cap 函数可获取切片容量

    	names := []string{1: "赵昌建", 10: "sen"}
    	fmt.Printf("%T
    ", names)
    	fmt.Printf("%q
    ", names)
    
    	fmt.Println(len(names)) //11
    	fmt.Println(cap(names)) //11
    
    遍历

    可以通过 for+len+访问方式或 for-range 方式对切片中元素进行遍历

    	names := []string{1: "赵昌建", 10: "sen"}	
    	for i := 0; i < len(names); i++ {
    		fmt.Println(i, names[i])
    	}
    
    	for v := range names {
    		fmt.Println(v, names[v])
    	}
    
    	for i, v := range names {
    		fmt.Println(i, v)
    	}
    
    切片元素

    slice[start:end]用于创建一个新的切片,end <= src_cap,可以增加长度

            teachers := [...]string{"qq", "wusi", "ads", "ws", "dd"}
    
    	teachers00 := teachers[:]
    
    	teachers01 := teachers[0:3]
    	teachers02 := teachers[1:4]
    	teachers03 := teachers00[1:3]
    
    	fmt.Printf("%q
    ", teachers) //["qq" "wusi" "ads" "ws" "dd"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers), cap(teachers), teachers) //5, 5, ["qq" "wusi" "ads" "ws" "dd"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers00), cap(teachers00), teachers00) //5, 5, ["qq" "wusi" "ads" "ws" "dd"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers01), cap(teachers01), teachers01) //3, 5, ["qq" "wusi" "ads"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers02), cap(teachers02), teachers02) //3, 4, ["wusi" "ads" "ws"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers03), cap(teachers03), teachers03) //2, 4, ["wusi" "ads"]
    	// 新创建切片长度和容量计算:len: end-start, cap: src_cap-start
    

    切片共享底层数组,若某个切片元素发生变化,则数组和其他有共享元素的切片也会发生变化

            eachers := [...]string{"qq", "wusi", "ads", "ws", "dd"}
    
    	teachers00 := teachers[:]
    
    	teachers01 := teachers[0:3]
    	teachers02 := teachers[1:4]
    	teachers03 := teachers00[1:3]
    
    	fmt.Printf("%q
    ", teachers) //["qq" "wusi" "ads" "ws" "dd"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers), cap(teachers), teachers) //5, 5, ["qq" "wusi" "ads" "ws" "dd"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers00), cap(teachers00), teachers00) //5, 5, ["qq" "wusi" "ads" "ws" "dd"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers01), cap(teachers01), teachers01) //3, 5, ["qq" "wusi" "ads"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers02), cap(teachers02), teachers02) //3, 4, ["wusi" "ads" "ws"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers03), cap(teachers03), teachers03) //2, 4, ["wusi" "ads"]
    
    	teachers01[2] = "小阮"
    	fmt.Printf("%q
    ", teachers) //["qq" "wusi" "小阮" "ws" "dd"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers), cap(teachers), teachers) //5, 5, ["qq" "wusi" "小阮" "ws" "dd"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers00), cap(teachers00), teachers00) //5, 5, ["qq" "wusi" "小阮" "ws" "dd"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers01), cap(teachers01), teachers01) //3, 5, ["qq" "wusi" "小阮"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers02), cap(teachers02), teachers02) //3, 4, ["wusi" "小阮" "ws"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers03), cap(teachers03), teachers03) //2, 4, ["wusi" "小阮"]
    

    slice[start​ : end : cap​]可用于限制新切片的容量值, end<=cap<= src_cap

    新创建切片长度和容量计算:len: end-start, cap: cap-start

    	teachers := [...]string{"qq", "wusi", "ads", "ws", "dd"}
    
    	teachers00 := teachers[:]
    
    	teachers01 := teachers[0:3]
    	teachers02 := teachers[1:4]
    	teachers03 := teachers00[1:3]
    
    
    	fmt.Printf("%q
    ", teachers) //["qq" "wusi" "ads" "ws" "dd"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers), cap(teachers), teachers) //5, 5, ["qq" "wusi" "ads" "ws" "dd"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers00), cap(teachers00), teachers00) //5, 5, ["qq" "wusi" "ads" "ws" "dd"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers01), cap(teachers01), teachers01) //3, 5, ["qq" "wusi" "ads"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers02), cap(teachers02), teachers02) //3, 4, ["wusi" "ads" "ws"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers03), cap(teachers03), teachers03) //2, 4, ["wusi" "ads"]
    
    
    	teachers04 := teachers[1:4:5]
    	teachers05 := teachers[1:3:3]
    	fmt.Printf("%d, %d, %q
    ", len(teachers04), cap(teachers04), teachers04) //3, 4, ["wusi" "ads" "ws"]
    	fmt.Printf("%d, %d, %q
    ", len(teachers05), cap(teachers05), teachers05) //2, 2, ["wusi" "ads"]
    
    添加元素

    使用 append 对切片增加一个或多个元素并返回修改后切片,当长度在容量范围内时只增加长度,容量和底层数组不变。当长度超过容量范围则会创建一个新的底层数组并对容量进行智能运算(元素数量>1024 时,约按原容量 1 倍增加,<1024 时约按原容量 0.25倍增加),append 分配新的切片来保证已有切片元素和新增元素的存储。因此,返回的切片可能已经指向一个不同的相关数组了。

    append 方法总是返回成功,除非系统内存耗尽了。append操作如果导致分配新的切片来保证已有切片元素和新增元素的存储,那么新的slice已经和原来slice没有任何关系,即使修改了数据也不会同步。append操作后,有没有生成新的slice需要看原有slice的容量是否足够,请见下面代码。

    // 切片操作内存原理
    package main
    import "fmt"
    func main() {
        s1 := []int{1, 2, 3}
        fmt.Println(len(s1), cap(s1), s1) // 输出 3 3 [1 2 3]
        s2 := s1[1:]
        fmt.Println(len(s2), cap(s2), s2) // 输出 2 2 [2 3]
        for i := range s2 {
            s2[i] += 20
        }
        // s2的修改会影响到数组数据,s1输出新数据
        fmt.Println(s1) // 输出 [1 22 23]
        fmt.Println(s2) // 输出 [22 23]
        s2 = append(s2, 4) // append  导致了slice 扩容
        for i := range s2 {
            s2[i] += 10
        }
        // s1 的数据现在是陈旧的老数据,而s2是新数据,他们的底层数组已经不是同一个了。
        fmt.Println(s1) // 输出[1 22 23]
        fmt.Println(s2) // 输出[32 33 14]
    }
    /*程序输出
    3 3 [1 2 3]
    2 2 [2 3]
    [1 22 23]
    [22 23]
    [1 22 23]
    [32 33 14]
    */
    
    //切片操作底层原理
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	nums := []int{1, 2, 3, 4, 5}
    	nums2 := nums[1:3]
    	fmt.Println(cap(nums2)) //4 切片容量=原来的nums容量-start
    	nums2 = append(nums2, 100) //切片操作和原来的切片共享存储空间
    	fmt.Println(nums2) //[2 3 100]
    	fmt.Println(nums) //[1 2 3 100 5]
    }
    

    解包 => 切片操作

    slice[start:end]
    // start=0 start省略
    // end=len() end省略
    
    package main
    
    import "fmt"
    
    func main() {
    	nums := []int{1, 2, 3}
    	nums2 := []int{3, 4, 5}
    
    	nums = append(nums, 100, 101, 102, 103)
    	// for _, v := range nums2 {
    	// 	nums = append(nums, v)
    	// }
    	// fmt.Println(nums, nums2)
    	// 解包 => 切片操作
    	nums = append(nums, nums2...)
    	// nums = append(nums, nums2[0], nums2[1], nums2[2], ..., nums2[len()-1])
    	fmt.Println(nums, nums2)
    
    	nums = append(nums[:2], nums[3:]...)
    	fmt.Println(nums)
    }
    
    删除元素

    使用copy复制切片删除,复制元素数量为src元素数量和dest元素数量的最小值

    copy(dst, src) 如果src多于des,多的不复制。如果src少于des,没有复制到的保留原值

    // 删除元素
    	var names []string
    	names = []string{1: "休息", 10: "sen"}
    	names = append(names, "小软")
        // 切片操作
        // names[start:end] names中从start开始到end-1所有元素组成的切片
        // names[1:10]
        //			0	1						   9   10	 11
        // names = ["" "休息" "" "" "" "" "" "" "" "" "sen" "小软"]
        // [names[1], names[2], ... names[9]]
    	fmt.Printf("%q
    ", names[1:10]) //["休息" "" "" "" "" "" "" "" ""]
    	fmt.Println(len(names)) // 切片长度12
    	names = names[1:len(names)] //["休息" "" "" "" "" "" "" "" "" "sen" "小软"]
    	fmt.Printf("%q
    ", names)
    
    // 删除索引为0 如果索引为len-1元素 删除首尾
    	// 0, len(names)-1
    	names = names[0 : len(names)-1] //["休息" "" "" "" "" "" "" "" "" "sen"]
    	fmt.Printf("%q
    ", names)
    
    	nums := []int{0, 1, 2, 3, 4, 5}
    
    // 删除中间的元素
    	// 删除3
    	copy(nums[3:], nums[4:]) // 切片操作和原来的切片共享存储空间 [0 1 2 4 5 5]
    	nums = nums[:len(nums)-1] //删除最后一个元素
    	fmt.Println(nums) //[0 1 2 4 5]
    
    容量
    package main
    
    import "fmt"
    
    func main() {
    	nums := []int{1, 2, 3, 4, 5}
    	fmt.Println(len(nums), cap(nums)) //5 5
    	nums = append(nums, 6)
    	fmt.Println(len(nums), cap(nums)) //6 10容量扩大一倍
    	nums = append(nums, 7)
    	fmt.Println(len(nums), cap(nums))
    	nums = append(nums, 7)
    	fmt.Println(len(nums), cap(nums))
    	nums = append(nums, 7)
    	fmt.Println(len(nums), cap(nums))
    	nums = append(nums, 7)
    	fmt.Println(len(nums), cap(nums))
    	nums = append(nums, 7)
    	fmt.Println(len(nums), cap(nums)) //11 20容量扩一倍
    }
    
    make
    package main
    
    import "fmt"
    
    func main() {
    	// make
    	// 2个参数: make(type, len)
    	// 3个参数: make(type, len, cap)
    	nums := make([]int, 3)
    	fmt.Println(len(nums), cap(nums)) // 3 3
    	fmt.Println(nums) // [0 0 0]
    
    	nums2 := make([]int, 2, 5)
    	fmt.Println(len(nums2), cap(nums2)) // 2 5
    	fmt.Println(nums2) // [0, 0]
    
    	// 切片底层原理
    	nums3 := nums2           	// [0, 0]
    	nums3 = append(nums3, 3)
    	fmt.Println(nums2, nums3) 	// [0, 0] [0, 0, 3]
    	nums2 = append(nums2, 4) 	// [0, 0, 4]
    	fmt.Println(nums3)       	// [0, 0, 4]
    	fmt.Println(nums2)			// [0, 0, 4]
    }
    

    空白标识符无法打印,无法使用

    //复制nums中所有数据到nums2,且两个不会相互影响
    //v1
    	nums := []int{1, 2, 3, 4, 5}
    	nums2 := make([]int, len(nums)) // []int{0, 0, 0, 0, 0}
    	for i, v := range nums {
    		nums2[i] = v
    	}
    	nums2[1] = 100
    	fmt.Println(nums, nums2) //[1 2 3 4 5] [1 100 3 4 5]
    	
    //v2
    	nums := []int{1, 2, 3, 4, 5}
    	nums2 := make([]int, 0, len(nums))
    	// 空白标识符
    	for _, v := range nums {
    		nums2 = append(nums2, v)
    	}
    	// fmt.Println(nums2)
    	nums2[1] = 100
    	fmt.Println(nums, nums2) //[1 2 3 4 5] [1 100 3 4 5]
    
    切片操作

    切片最大end <= 容量大小

    package main
    
    import "fmt"
    
    func main() {
    	nums := make([]int, 5, 10) // len=5, cap=100
    	// slice[start:end]
    	// 0 <= start <= end <= cap
    	// len := end-start
    	// cap := cap-start
    	// nums2 := nums[2:5]
    	// fmt.Println(nums2, len(nums2), cap(nums2)) //[0 0 0] 3 8
    
    
    	// slice[start:end:cap_end]
    	// 0 <= start <= end <= cap_end <= cap
    	// len := end - start
    	// cap := cap_end - start
    	nums2 := nums[2:5:5]
    	fmt.Println(nums2, len(nums2), cap(nums2)) //[0 0 0] 3 3
    	nums2 = append(nums2, 1000)
    	nums = append(nums, 1)
    	fmt.Println(nums2, nums) //[0 0 0 1000] [0 0 0 0 0 1]
    }
    
    多维切片

    数组中的元素可以是切片

    切片中的元素可以是切片

    package main
    
    import "fmt"
    
    func main() {
    	var nums [2][]int
    	fmt.Println(nums) // [[] []]
    	nums[0] = append(nums[0], 1)
    	nums[1] = append(nums[1], 100)
    	fmt.Println(nums) // [[1] [100]]
    
    	var nums2 [][2]int
    	fmt.Println(nums2) // []
    	nums2 = append(nums2, [2]int{1, 2})
    	nums2 = append(nums2, [2]int{10, 20})
    	fmt.Println(nums2) // [[1 2] [10 20]]
    
    	var nums3 [][]int
    	nums3 = append(nums3, []int{})
    	nums3 = append(nums3, []int{})
    	nums3 = append(nums3, []int{})
    	nums3[0] = append(nums3[0], 1, 2, 3)
    	nums3[1] = append(nums3[1], 2, 3, 4)
    	fmt.Println(nums3) // [[1 2 3] [2 3 4] []]
    
    	var nums4 [1][]int
    	nums4[0] = []int{1, 2, 3}
    
    	fmt.Println(nums4) // [[1 2 3]]
    
    	var nums5 [0]int
    	fmt.Println(nums5) //[]
    }
    
    
    队列

    先进先出

    package main
    
    import "fmt"
    
    func main() {
    	// 队列
    	// 先进先出
    	queue := []int{}
    
    	queue = append(queue, 1)
    	queue = append(queue, 3)
    	queue = append(queue, 2)
    	queue = append(queue, 6)
    
    	// append 右边进入
    	// 1 -> [1]
    	// 2 -> [1, 2]
    	// 3 -> [1, 2, 3]
    	// 从左边出
    	// <- 1  [2, 3]
    	// <- 2 [3]
    	// <- 3 []
    	for len(queue) != 0 {
    		fmt.Println(queue[0])
    		queue = queue[1:]
    	}
    
    	fmt.Println("over")
    }
    
    
    堆栈

    先进后出

    package main
    
    import "fmt"
    
    func main() {
    	stack := []int{}
    	// 先进后出
    	// append 从右边进入
    	// 1 -> [1]
    	// 2 -> [1, 2]
    	// 3 -> [1, 2, 3]
    	stack = append(stack, 1)
    	stack = append(stack, 2)
    	stack = append(stack, 3)
    	// 从右边出
    	// 3, 2, 1
    	for len(stack) != 0 {
    		fmt.Println(stack[len(stack)-1])
    		stack = stack[:len(stack)-1]
    	}
    }
    

    映射map

    哈希表是一种巧妙并且实用的数据结构。它是一个无序的key/value对的集合,其中所有的key都是不同的,然后通过给定的key可以在常数时间复杂度内检索、更新或删除对应的value。

    在Go语言中,一个map就是一个哈希表的引用,map类型可以写为map[K]V,其中K和V分别对应key和value。map中所有的key都有相同的类型,所有的value也有着相同的类型,但是key和value之间可以是不同的数据类型。其中K对应的key必须是支持==比较运算符的数据类型,所以map可以通过测试key是否相等来判断是否已经存在。虽然浮点数类型也是支持相等运算符比较的,但是将浮点数用做key类型则是一个坏的想法,正如最坏的情况是可能出现的NaN和任何浮点数都不相等。对于V对应的value数据类型则没有任何的限制。

    声明

    map 声明需要指定组成元素 key 和 value 的类型,在声明后,会被初始化为 nil,表示暂不存在的映射

    package main
    
    import "fmt"
    
    func main() {
    	var tels map[string]string
    	var points map[[2]int]float64
    	fmt.Printf("%T, %t, %v
    ", tels, tels == nil, tels) //map[string]string, true, map[]
    	fmt.Printf("%T, %t, %v
    ", points, points == nil, points) //map[[2]int]float64, true, map[]
    
    }
    

    初始化

    (1)使用字面量初始化:map[type]type{k1:v1, k2:v2, …, kn:vn}
    (2)使用字面量初始化空映射:map[type]type{}
    (3)使用make函数初始化,make(map[type]type),通过make函数创建映射
    
    package main
    
    import "fmt"
    
    func main() {
    	// var
    	var tels map[string]string
    	var points map[[2]int]float64
    
    	tels = map[string]string{"qq": "1228905807", "vx": "rxg111888"}
    	fmt.Printf("%q
    ", tels) // map["qq":"1228905807" "vx":"rxg111888"]
    
    	points = map[[2]int]float64{{1, 2}: 3, {4, 5}: 6}
    	fmt.Printf("%q
    ", points) // map[['x01' 'x02']:%!q(float64=3) ['x04' 'x05']:%!q(float64=6)]
    	fmt.Println(points) //	map[[1 2]:3 [4 5]:6]
    
    	//	map[k]v{k1: v1, k2: v2}
    	scores := map[string]int{"rxg": 80, "fyq": 100}
    	fmt.Println(scores) // map[fyq:100 rxg:80]
    
    	// 空映射
    	heights := map[string]float64{}
    	fmt.Println(heights) // map[]
    
    	// make
    	weights := make(map[string]float64)
    	fmt.Println(weights) // map[]
    }
    

    操作

    获取元素的数量
    	var names map[string]string = map[string]string{"Go01": "刘备"}
    	fmt.Println(len(names)) // 1
    
    访问、添加、修改元素

    通过 key 访问元素时可接收两个值,第一个值为 value,第二个值为 bool 类型表示元素是否存在,若存在为 true,否则为 false

    	var names map[string]string = map[string]string{"Go01": "刘备"}
    	// key 访问元素
    	// key 添加或者修改元素
    	fmt.Printf("%q
    ", names["Go05"]) // ""
    	names["Go05"] = "关羽"
    	names["Go01"] = "liubei"
    	fmt.Println(names) // map[Go01:liubei Go05:关羽]
    	names["Go02"] = ""
    	fmt.Println("-",names["Go02"], names["Go03"], names["Go05"]) // -  关羽
    	v, ok := names["Go02"] // v = k => value k不存在返回value type 0值, ok bool
    	fmt.Println(v, ok) //  true
    	v, ok = names["Go03"] // v = k => value k不存在返回value type 0值, ok bool
    	fmt.Println(v, ok) //  false
    
    删除元素delete
    	var names map[string]string = map[string]string{"Go01": "刘备"}
    	fmt.Println(names) // map[Go01:刘备]
    	delete(names, "Go01")
    	fmt.Println(names) // map[]
    
    遍历

    注意: 遍历map时的元素顺序与添加键值对的顺序无关

    	var names map[string]string = map[string]string{"Go01": "刘备"}
    	for k := range names {
    		fmt.Println(k, names[k])
    	}
    
    	for k, v := range names {
    		fmt.Println(k, v)
    	}
    	fmt.Println("--------------")
    	var scores = make(map[string]int)
    	scores["Go028"] = 80
    	scores["Go027"] = 82
    	scores["Go026"] = 82
    	scores["Go025"] = 82
    	scores["Go029"] = 82
    	
    	for k, v := range scores {
    		fmt.Println(k, v)
    	}
    	scores["Go024"] = 82
    	scores["Go128"] = 80
    	scores["Go127"] = 82
    	scores["Go126"] = 82
    	scores["Go125"] = 82
    	scores["Go129"] = 82
    	scores["Go124"] = 82
    
    	fmt.Println("--------------")
    	for k, v := range scores {
    		fmt.Println(k, v)
    	}
    
  • 相关阅读:
    数据结构之链表
    非常好的Java反射例子
    return和finally的执行和联系
    struts2中的OGNL详解
    解耦与耦合的你我他
    struts2案例
    《使用Hibernate开发租房系统》内部测试笔试题
    一对多双向关联关系
    Oracle基本数据类型
    transactionManager的type与dataSource的type
  • 原文地址:https://www.cnblogs.com/Otiger/p/13766147.html
Copyright © 2020-2023  润新知