走进Go语言基础(2) | 青训营笔记

75 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

内容源于青训营课堂视频以及一些go文档和自己的经验、理解,若有错误欢迎及时指出

2.4slice

由于数组的局限性(长度固定且与类型绑定),所以产生了切片类型

切片是一个有相同类型元素的可以任意更改长度的序列,是基于数组的封装,也有更多丰富的操作

可以用make来创建一个切片,可以像数组一样取值,可以使用append来追加元素,一般用于快速地操作一块数据集合

  • 切片是引用类型,但自身是结构体,是值传递

  • 注意使用append的时候必须把返回值赋给原数组

    • slice底层原理是存储了长度、容量加一个指向底层数组的指针,如果容量不够的话会扩容并返回新的slice
  • 可以像python一样的切片,但不支持负索引

创建方式

//声明切片
var s1 []int

//初始化赋值
s2 := []int{1, 2, 3}

//使用make()创建
//make([]Type, size, cap)
//区别长度和容量
var s3 = make([]int, 2, 6)

//基于数组切片得到s4
array := [4]int{1, 2, 3, 4}
s4 := array[1:3]

长度是这个切片包含的元素个数,容量是这个切片完全扩容后的大小(长度+底层数组剩下的空间)

len()求长度 cap()求容量 判断空切片使用 len(a) == 0

  • 一个长度和容量都为0的切片不一定是nil,一个nil值的切片只能说明没有底层数组
    • s1 := []int{} s1 != nil
    • s2 := make(int[], 0) s2 != nil
  • 扩容策略是按照1,2,4,8成倍自动扩容

赋值拷贝添加

直接赋值的话是共享底层数组s1 := s2

使用内置copy()才是分配新的地址空间保存 copy(newslice, oldslice)

s1 := []int{1, 2, 3}

删除元素

目标元素索引是Index

a = append(a[:index], a[index+1:]...)

2.5map

map是一种完全无序、基于k-v的数据结构,引用类型,初始化后才能使用

m := make(map[string]int)
  • 当索引不存在的键的时候值为对应类型的空值

    m := make(map[string]int)
    fmt.Println(m["unknown"]) // 0
    
  • 使用range遍历键值对

    //遍历,顺序随机
    for k, v := range M {
    fmt.Println(k, v)
    }
    
  • 使用delete()删除键值对

    //删除键值对
    delete(m, "one")
    

2.6函数

特点

  • 支持不定参数

  • 支持多返回值

  • 支持定义返回值名称

  • 支持匿名和闭包

  • 函数可以赋值给变量,是一种类型

  • 无重载

  • 无默认参数

参数

引用传递与值传递

golang中map、slice、chan、指针、interface默认以引用的方式传递——赋值地址

不定参数

使用...

func function(args ...int) {    //0个或多个参数
}

而args是一个切片类型,可通过切片的操作进行参数访问

当使用slice作为变参的时候需要使用...将slice展开

s := []int{1, 2, 3}
function(s...)

任意类型的不定参数

使用interface{}传递任意类型数据

func function(args ...interface{}) {
}

返回值

  • 没有参数的return返回变量当前值

    func add(a int, b int) (c int) {
    	//c在返回值那里声明的,“裸”返回
    	c = a + b
    	return
    }
    
  • 返回值只能一个个接收,不能使用容器,但可以通过_忽略

返回顺序

func add3(x, y int) (z int) {
	defer func() {
		//z = 4
		z += 100
		fmt.Println(z) // z = 104
	}()

	z = x + y
	fmt.Println(z) //3
	//return的内容执行完了赋值给z了再调用defer
	return z + 1
}

z := add3(1, 2)
fmt.Println(z + 1) //105

匿名函数

没有名字的函数,可以直接像普通变量一样传递使用

延时调用

defer,在return之前才执行,常用来做资源清理

  • 关闭文件句柄

  • 释放锁

  • 释放数据库连接

  • 同步内存和磁盘(zap)

    defer logger.Sync()

多个defer会形成栈,先定义的后执行

异常处理

defer()recover()

处理异常后,逻辑恢复到defer后的那个点

recover只能在defer函数那一层中直接使用,其他方式都是返回空值