golang容器

数组

声明:var 数组变量名 [元素数量]Type

代码实例:

func main() {
    var a [3]int
    fmt.Println(a[2])
    fmt.Println(len(a))
    /**
    打印索引和元素
     */
    for i,v := range a {
        fmt.Printf("%d,%d\n",i,v)
    }
    /**
    打印元素
     */
    for _,v := range a{
        fmt.Printf("%d\n",v)
    }
    /**
    比较数组相等
     */
    nums1 := [...]int{1,2,3}
    nums2 := [...]int{1,2,3}
    fmt.Println(nums1==nums2)
}

注意:golang中数组可以直接比较是否相等,但是java不可以

多维数组

声明:var array_name [size1][size2]...[sizen] array_type

代码实例:

func main() {
    // 声明一个二维整型数组,两个维度的长度分别是 4 和 2
    var array [4][2]int
    // 使用数组字面量来声明并初始化一个二维整型数组
    array = [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}
    // 声明并初始化数组中索引为 1 和 3 的元素
    array = [4][2]int{1: {20, 21}, 3: {40, 41}}
    // 声明并初始化数组中指定的元素
    array = [4][2]int{1: {0: 20}, 3: {1: 41}}

    //fmt.Println(array[1])

    for _,v := range array{
        for x, y := range v{
            fmt.Printf("%d, %d\n", x, y)
        }
    }
}

切片

切片(slice)是对数组的一个连续片段的引用,所以切片是一个引用类型(因此更类似于 C/C++ 中的数组类型,或者 Python 中的 list 类型),这个片段可以是整个数组,也可以是由起始和终止索引标识的一些项的子集,需要注意的是,终止索引标识的项不包括在切片内。

语法:slice [开始位置 : 结束位置]

语法说明如下:

  • slice:表示目标切片对象;
  • 开始位置:对应目标切片对象的索引;
  • 结束位置:对应目标切片的结束索引。

从数组上创造切片:

var a = [3]int{1, 2,3} b := a[:2]

声明新的切片:

var strList []string可以使用append()函数进行切片添加新的值,初始长度为0

使用 make() 函数构造切片:

语法:make( []Type, size, cap ),其中 Type 是指切片的元素类型,size 指的是为这个类型分配多少个元素,cap 为预分配的元素数量,这个值设定后不影响 size,只是能提前分配空间,降低多次分配空间造成的性能问题。

func main() {
    a := make([]int, 2)
    a = append(a, 20,10)
    fmt.Println(a)
}

输出如下:[0 0 20 10]

切片添加元素

var a []int
a = append(a, 1) // 追加1个元素
a = append(a, 1, 2, 3) // 追加多个元素, 手写解包方式
a = append(a, []int{1,2,3}...) // 追加一个切片, 切片需要解包
a = append([]int{0}, a...) // 在开头添加1个元素
a = append([]int{-3,-2,-1}, a...) // 在开头添加1个切片
a = append(a[:i], append([]int{x}, a[i:]...)...) // 在第i个位置插入x
a = append(a[:i], append([]int{1,2,3}, a[i:]...)...) // 在第i个位置插入切片

切片复制

语法:opy( destSlice, srcSlice []T) int

func main() {
    slice1 := []int{1, 2, 3, 4, 5}
    slice2 := []int{5, 4, 3}
    copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中
    copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置
    fmt.Println(slice2)
}

从切片中删除元素

从开头删除:

a = []int{1, 2, 3}
a = a[1:] // 删除开头1个元素
a = a[N:] // 删除开头N个元素
a = []int{1, 2, 3}
a = append(a[:0], a[1:]...) // 删除开头1个元素
a = append(a[:0], a[N:]...) // 删除开头N个元素
a = []int{1, 2, 3}
a = a[:copy(a, a[1:])] // 删除开头1个元素
a = a[:copy(a, a[N:])] // 删除开头N个元素

从中间删除:

a = []int{1, 2, 3, ...}
a = append(a[:i], a[i+1:]...) // 删除中间1个元素
a = append(a[:i], a[i+N:]...) // 删除中间N个元素
a = a[:i+copy(a[i:], a[i+1:])] // 删除中间1个元素
a = a[:i+copy(a[i:], a[i+N:])] // 删除中间N个元素

从尾部删除:

a = []int{1, 2, 3}
a = a[:len(a)-1] // 删除尾部1个元素
a = a[:len(a)-N] // 删除尾部N个元素

range 关键字

循环迭代切片

func main() {
    slice := []int{10, 20, 30, 40}
    // 迭代每一个元素,并显示其值
    for index, value := range slice {
        fmt.Printf("Index: %d Value: %d\n", index, value)
    }
}

golang中的map

Go语言中 map 是一种特殊的数据结构,一种元素对(pair)的无序集合,pair 对应一个 key(索引)和一个 value(值),所以这个结构也称为关联数组或字典,这是一种能够快速寻找值的理想结构,给定 key,就可以迅速找到对应的 value。

声明:var mapname map[keytype]valuetype

代码示例:

func main() {
    var mapLit map[string]int
    //var mapCreated map[string]float32
    var mapAssigned map[string]int
    mapLit = map[string]int{"one": 1, "two": 2}
    mapCreated := make(map[string]float32)
    mapAssigned = mapLit
    mapCreated["key1"] = 4.5
    mapCreated["key2"] = 3.14159
    mapAssigned["two"] = 3
    fmt.Printf("Map literal at \"one\" is: %d\n", mapLit["one"])
    fmt.Printf("Map created at \"key2\" is: %f\n", mapCreated["key2"])
    fmt.Printf("Map assigned at \"two\" is: %d\n", mapLit["two"])
    fmt.Printf("Map literal at \"ten\" is: %d\n", mapLit["ten"])
}

map遍历:

scene := make(map[string]int)
scene["route"] = 66
scene["brazil"] = 4
scene["china"] = 960
for k, v := range scene {
    fmt.Println(k, v)
}

map元素删除:

cene := make(map[string]int)
// 准备map数据
scene["route"] = 66
scene["brazil"] = 4
scene["china"] = 960
delete(scene, "brazil")
for k, v := range scene {
    fmt.Println(k, v)
}

golang链表

列表是一种非连续的存储容器,由多个节点组成,节点通过一些变量记录彼此之间的关系,列表有多种实现方法,如单链表、双链表等。

方 法 功 能
InsertAfter(v interface {}, mark Element) Element 在 mark 点之后插入元素,mark 点由其他插入函数提供
InsertBefore(v interface {}, mark Element) Element 在 mark 点之前插入元素,mark 点由其他插入函数提供
PushBackList(other *List) 添加 other 列表元素到尾部
PushFrontList(other *List) 添加 other 列表元素到头部
func main() {
    l := list.New()
    // 尾部添加
    l.PushBack("canon")
    // 头部添加
    l.PushFront(67)
    // 尾部添加后保存元素句柄
    element := l.PushBack("fist")
    // 在fist之后添加high
    l.InsertAfter("high", element)
    // 在fist之前添加noon
    l.InsertBefore("noon", element)
    // 删除
    l.Remove(element)
}

遍历链表:

for i := l.Front(); i != nil; i = i.Next() {
    fmt.Println(i.Value)
}

Go语言nil:空值/零值

在Go语言中,布尔类型的零值(初始值)为 false,数值类型的零值为 0,字符串类型的零值为空字符串"",而指针、切片、映射、通道、函数和接口的零值则是 nil。

nil 是Go语言中一个预定义好的标识符,有过其他编程语言开发经验的开发者也许会把 nil 看作其他语言中的 null(NULL),其实这并不是完全正确的,因为Go语言中的 nil 和其他语言中的 null 有很多不同点。

/**
    nil 标识符是不能比较的
    运行报错
     */
    // fmt.Println(nil==nil)

    /**
    nil 并不是Go语言的关键字或者保留字,也就是说我们可以定义一个名称为 nil 的变量
     */
    var nil = errors.New("my god")
    fmt.Println(nil)

    /**
    nil 没有默认类型
    输出:*errors.errorString(0x4df300,0xc0000321d0)
     */

    fmt.Printf("%T", nil)
    print(nil)

    /**
    不同类型 nil 的指针是一样的
    输出:0x0 0x0
     */
    var arr []int
    var num *int
    fmt.Printf("%p\n", arr)
    fmt.Printf("%p", num)
    /**
    不同类型的 nil 是不能比较的
    编译报错
     */

    var m map[int]string
    var ptr *int
    fmt.Printf(m == ptr)

Go语言make和new关键字的区别及实现原理

Go语言中 new 和 make 是两个内置函数,主要用来创建并分配类型的内存。在我们定义变量的时候,可能会觉得有点迷惑,不知道应该使用哪个函数来声明变量,其实他们的规则很简单,new 只分配内存,而 make 只能用于 slice、map 和 channel 的初始化