美文网首页
go 高级使用

go 高级使用

作者: 将军红 | 来源:发表于2020-01-13 00:26 被阅读0次

1.切片 VS 数组

列表 数组 切片
类型 值类型 引用类型
长度 初始化后长度是固定的 长度可以变化
初始化方法① [5] int {1,2} s :=make([]int,len,cap) //内置函数make()初始化 .初始化时len=cap,在追加元素时如果容量cap不足时将按len的2倍扩容
初始化方法② [...] int {1,2,3,4,5};//有....自动计算 s :=[] int {1,2,3 } //直接初始化切片,[]表示是切片类型,{1,2,3}初始化值依次是1,2,3.其cap=len=3
初始化方法③ [5] int { 2:1,3:2,4:3}; s := arr[startIndex:endIndex] //将arr中从下标startIndex到endIndex-1 下的元素创建为一个新的切片
初始化方法④ [...] int {2:1,4:3}//长度为5的数组,起元素值依次为:0,0,1,0,3。由于指定了最大索引4对应的值3,根据初始化的元素个数确定其长度为5赋值与使用 xx
访问方法① 通过下标访问元素,可修改其元素值:arr[1] 同左
访问方法② 通过for遍历数组元素:for index, value := range arr 同左
其他 你将一个数组赋值给另外一个数组,那么,实际上就是将整个数组拷贝一份(匿名拷贝)改变原值,则新值不会变 添加:①s :=append(s,1,2,3,4);②s :=append(s,s1...)

切片本身并不是动态数组或者数组指针。它内部实现的数据结构通过指针引用底层数组,设定相关属性将数据读写操作限定在指定的区域内。切片本身是一个只读对象,其工作机制类似数组指针的一种封装。

切片三要素:
指针:指向地址
长度:len
容量:cap

切片初始化,len=cap
切片是引用类型(新地址,指向原地址上的值),最大的特点是,引用的地址上值改变,切片也会改变

slice := []int{1, 2, 3} //刚开始len=cap
newSlice := append(slice, 4, 5) //扩容,触发了拷贝(新建地址)
newnewSlice := slice[:] //切片的引用
slice[0] = 88
fmt.Printf("slice:%+v, newSlice:%+v, newnewSlice:%+v\n", slice, newSlice, newnewSlice)
//slice:[88 2 3], newSlice:[1 2 3 4 5], newnewSlice:[88 2 3]

另外,数组作为函数的参数,那么实际传递的参数是一份数组的拷贝,而不是数组的指针。
所以函数中对数组改变,返回后数组不会改变

A(arr)

func A(arr []int){
  arr[0]=9
}

1.切片vs数组
2.切片是引用传递,所以它们不需要使用额外的内存并且比使用数组更有效率
3.空切片 vs nil切片
4.切片扩容:
4.1 扩容策略

如果切片的容量小于 1024 个元素,于是扩容的时候就翻倍增加容量。上面那个例子也验证了这一情况,总容量从原来的4个翻倍到现在的8个。
一旦元素个数超过 1024 个元素,那么增长因子就变成 1.25 ,即每次增加原来容量的四分之一。(××××××××××错,发现了1,2,4,6,8规律)
注意:扩容扩大的容量都是针对原来的容量而言的,而不是针对原来数组的长度而言的。

4.2扩容是生成全新的内存地址还是在原来的地址后追加?
4.2.1 slice创建方法一:【分扩容情况,是否扩容】
slice := []int{10, 20, 30, 40}
newSlice := append(slice, 50)
Go 默认会先开一片内存区域,把原来的值拷贝过来,然后再执行 append() 操作。这种情况丝毫不影响原数组。

4.2.2 切片字面量创建【新地址】
由于原数组还有容量可以扩容,所以执行 append() 操作以后,会在原数组上直接操作,所以这种情况下,扩容以后的数组还是指向原来的数组。
array := [4]int{10, 20, 30, 40}
slice := array[0:2]
newSlice := append(slice, 50)

详细参考链接

func main() {
    arrayA := [2]int{100, 200}
    testArrayPoint(&arrayA)   // 1.传数组指针
    arrayB := arrayA[:]
    testArrayPoint(&arrayB)   // 2.传切片 ****
    fmt.Printf("arrayA : %p , %v\n", &arrayA, arrayA)
}

func testArrayPoint(x *[]int) {
    fmt.Printf("func Array : %p , %v\n", x, *x)
    (*x)[1] += 100
}

打印结果:

func Array : 0xc4200b0140 , [100 200]
func Array : 0xc4200b0180 , [100 300]
arrayA : 0xc4200b0140 , [100 400]

并非所有时候都适合用切片代替数组,因为切片底层数组可能会在堆上分配内存,而且小数组在栈上拷贝的消耗也比make 消耗小

2. map

学习链接

sync/atomic的使用
Go之 unsafe.Pointer

  1. context
    学习链接

总结:

    1. 关于cancel
      withCance 会传递 cancel信号到子context中。
      如果某层context cancel了,则会向它的所有子值(或者说子节点)传达撤销信号。这些子值会如法炮制,把撤销信号继续传播下去。最后,这个Context值会断开它与其父值之间的关联。
  • 2.关于context 中的value
    设置传递时,会传递到所有子context中。
    取值key时,回去查找本context,如果没找到key,会向上去查找所有父的context查找

    1. 关于grpc的timeout
      客户端调用时,加了timeout参数,会在http2的header中添加grpc-timeout参数
      服务端获取参数,判断相关逻辑。

相关文章

网友评论

      本文标题:go 高级使用

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