make 也是用于内存分配的 ,只用于 chan、map 以及 slice 的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。
定义类型也可以使用 new 函数来分配空间,
指针(Pointer)本质上是一个指向某块计算机内存的地址。就像日常的门牌地址一样。只不过内存地址是一个数字编号,对应的是一个个字节(byte)。
因为指针和引用本质上也是值,字面意义上,Go 里面所有传递都是值传递。这句话正确却没有指导意义。
Go 里的赋值和传参,总是会把传递的值本身拷贝一份。
(直接)值传递:值发生了拷贝。对新值的任何修改,都不会影响原来的值。
除非这个值是一个结构体,结构体成员字段里有引用类型或者指针,那么对这个字段而言,则是引用传递/指针传递。
引用传递:元数据发生了拷贝,但底层的间接值没有拷贝,仍然共享。
对间接值的修改,会影响所有副本。(如,修改切片里的某个元素,就是修改了底层数组里的某个元素)
但对元数据的修改则不会影响其它副本。(如,对切片提取子切片,实际上修改了切片的访问范围)
有一种特殊的情况,就是修改元数据时改变了指向的间接值的指针,这之后对间接值的修改,都不再会影响其它副本。因为不再共享间接值。(如,对切片追加元素时,促发了底层数组的重新分配,指向了新的底层数组)
指针传递:
指针值(地址)发生了拷贝,共享指向的值。对间接值的修改,会影响所有副本。由于 Go 不允许对指针进行运算,不存在意外改变指针的情况。而如果是给指针赋新的值,后续的修改当然不再影响旧值指向的值。由于指针的机制透明,这点很好理解。
Go 的引用类型有 slice、map 和 chan,
读写锁用在读多写少的
channel 底层还是锁和队列
golang中的切片slice其实是数组arrays的一种抽象,所以要搞懂切片slice,就要先弄明白数组arrays。
数组arrays很好理解,就是一个固定长度、固定元素类型的数组
数组arrays在go中是值,而不是指针。
在go中你赋值或者传递数组arrays,都会对整个数组内容进行一份复制。所以为了避免无谓的复制,我们会传递数组的指针,而不是数组。
和声明数组的区别就是没有指定长度。可以使用范围来截取切片,例如s1[x:y],会将s1中x位的元素至y-1位的元素截取。
d := [2]int{11, 22} // 数组类型
s1 := []int{11, 22, 33} // 切片类型
fmt.Println(s1[:2]) // [11 22]
fmt.Println(s1[1:2]) // [22]
s := make([]int, 5),
append
如果不行,那么它会new一个新的底层数组,大小为之前cap的两倍,并将之前的元素复制进去。下面测试了下:
、减少内存 ,对于大数组来说
mydata := data[m:n]
r := make([]int, len(mydata))
copy(r, mydata)
return r
https://github.com/i-coder-robot/puzzle4go/blob/master/1-100/puzzle51-68/main.go
最终我们可以确认的是Go语言中所有的传参都是值传递(传值),都是一个副本,一个拷贝。因为拷贝的内容有时候是非引用类型(int、string、struct等这些),这样就在函数中就无法修改原内容数据;有的是引用类型(指针、map、slice、chan等这些),这样就可以修改原内容数据。
因为在Go 泛型没有支持之前,只能通过反射才能写出满足不同类型的函数。