make slicek
我记得这几乎是每个使用go的同学都会遇到的:
students := make([]Student, 0, 10)
students2 := make([]Student, x, 10)
make在slice的时候,会根据第二个参数的值, 使用这个类型默认的零值来构建对应数量的对象.0的时候,整个slice是0个元素, x的时候,是已经存在了x个元素(值为此类型的零值).
另外关于slice当做方法参数传递的时候,会复制slice自身,而不会复制底层依赖的数据就没什么可说的.
defer闭包
首先defer是倒序执行的
fun := func(t int) {
println(strconv.Itoa(t))
}
y := 10
//1.
defer fun(y)
//2
defer func() {
println("\n2.")
fun(y)
}()
y = 20
==>
2.
20
10
- 在压入defer栈的时候,已经复制了y的值10, 2.在压栈的时候是压入了函数, 函数引向外部的y变量.
同理
pointX := &SomeStrunct(123)
defer pointX.SomeMethod()
defer func() {
println("我是func包住的")
pointX.SomeMethod()
}
pointX = &SomeStruct(456)
==>
两个defer
按照顺序执行后输出
我是func包住的
456
123 // 这个是第一个defer输出的, pointX在压入栈的时候, 已经计算好pointX的值了.
defer函数可能是空指针
因为defer常备用来清理资源,但是如果某个资源创建失败, 它的defer如果还会执行的话, 写的不好,会报错:
xx , err:= createSomeResources()
不判断err
defer Close(xx) // err 不为nil的时候,xx是nil, 可能defer出错
变量类型
值类型,引用类型
值类型直接指向一块存有值的内存空间, 指针类型的内存空间里存着的是一块内存地址的位置, 指针类型自己存在一块内存空间, 所以自己也可以被取地址, 引用类型相当于指针类型的别名, 也可以被取地址, 但是这是它本身的地址, 而不是它所代表的数据的地址.
引用类型变量: slice, map, channel
除外都是值类型
因为值类型存在栈上,而引用类型的一般放堆上,所以, 需要主动分配内存.
对于值类型, 申明就可以 申明 + 分配内存
对于引用类型, 申明就只是申明, 还需要分配内存空间
分配空间又有两种方式:
- new
- make
new 它只接受一个参数,这个参数是一个类型,分配好内存后,返回一个指向该类型内存地址的指针。同时请注意它同时把分配的内存置为零,也就是类型的零值。new(int)
//slice
ss := new([]int)
println(ss) // [0/0]0x0 == nil
sss := append(ss, 2)
print(sss[0])
var yy []int
println(yy) // [0/0]0x0 == nil
yyy := append(yy, 3)
print(yyy[0])
// slice 特别的是不需要初始化也能append
//map
m := new(map[int]int)
println(*m) // 0x0 nil
ma := *m
ma[1] = 2 // panic
// map 就需要初始化
make也是用于内存分配的,但是和new不同,它只用于chan、map以及切片的内存创建,而且它返回的类型就是这三个类型本身, 而且是初始化过的,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。
注意,因为这三种类型是引用类型,所以必须得初始化,但不是置为零值,这个和new是不一样的. func make(t Type, size ...IntegerType) Type
从函数声明中可以看到,返回的还是该类型。
网友评论