版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/phantom_111/article/details/79475759
golang提供的内建函数new()和make()。二者做的是不同的事情并且应用于不同的类型,但是因为规则类似,所以在使用过程中经常容易混淆。
new
这是用来分配内存的内建函数,它不初始化内存,只是将其置零。也就是说,new(T)会为T类型分配置零的存储,并返回它的地址(*T)。在Go的术语中,其返回一个指向新分配的类型为T的指针,这个指针指向的内容的值为零。注意并不是指针为零 。
对于不同的数据类型,零值的意义是不同的:
//int的零值为0
pI := new(int)
fmt.Printf("int: %p, %d\n", pI, *pI)
//string的零值为空字符串
pS := new(string)
fmt.Printf("string: %p, %s, %t\n", pS, *pS, *pS == "")
//bool的零值为false
pB := new(bool)
fmt.Printf("bool: %p, %t\n", pB, *pB)
fmt.Println("Hello, playground")
使用及例子
使用
p := new(DataType)
//DataType包含基本的数据类型int,string等以及自定义的数据类型struct等
例子
func newInt() *int {
var i int
return &i
}
func main() {
i := newInt()
}
注意: 这里与C/C++不同,返回一个局部变量的地址在go语言是可以的,通过go run -gcflags=-m main.go
发现该变量已逃逸到堆,所以mian函数可以直接使用。
make
内建函数make(T, args)与new(T)的用途不同。它只用来创建slice、map和channel,并且返回一个初始化的(而不是置零),类型为T的值(而不是*T)。之所以有所不同,是因为这三个类型的背后引用了使用前必须初始化的数据结构。例如,slice是一个三元描述符,包含一个指向数据(在数组中)的指针,长度以及容量,在这些项被初始化之前,slice都是nil的。对于slice,map和channel,make初始化这些内部数据结构,并准备好可用的值。
使用及例子
使用
p := make(type, len, cap)
例子
//分配一个长度为10, 容量为100的slice结构,该slice引用包含前10个元素的数组
m := make([]int, 10, 100)
fmt.Printf("make's value %x\n",m )
//返回一个指向新分配的,被置零的slice结构体指针,即指向值为nil的slice指针
n := new([]int) //allocates slice structure, *p == nil , rarely userful
*n = append(*n, 10)
fmt.Printf("new's address:%p, vaule:%x\n", n, *n)
问题
以下代码是否存在问题?如果存在问题请改正?
type student struct {
Name string
Age int
}
func main() {
m := make(map[string]*student)
stus := []student{
{Name: "zhou", Age: 24},
{Name: "li", Age: 23},
{Name: "wang", Age: 22},
}
for _, stu := range stus {
m[stu.Name] = &stu
}
for _, v := range m {
fmt.Printf("%v", v)
}
}
结果打印:
&{wang 22}
&{wang 22}
&{wang 22}
原因分析:
创建map的类型为map[string]*int,而在通过for range对该map进行赋值的时候,只是把局部变量stu的地址赋值给map的value,而stu变量存储的内容必定为stus迭代的map的某一项的值,所以才会出现上述的打印结果。
改正方式:
//将遍历赋值的代码改为如下方式
for i, stu := range stus {
m[stu.Name] = &stus[i]
}