前言
一个简单的面试题
一、new函数可以创建引用类型吗?
大家都知道go语言中,New(T)是分配内存的内建函数,对于一个已经存在的变量可对其指针进行赋值 ,可以分配任意类型的数据。而引用类型map,slice,channel 是通过make函数来创建。这个题主要是想问New函数是否可以创建引用类型。
答案是可以创建引用类型的,至于能不能用就是另外一回事了,看几个例子吧。
二、示例
1. 声明map
代码如下(示例):
package _3review
import (
"fmt"
"testing"
)
func TestNewMap(t *testing.T) {
var intMap map[string]int // 声明map,没有分配内存的空映射
fmt.Printf("intMap: %p %#v \n", &intMap, intMap) //intMap: 0xc000012058 map[string]int(nil)
intMap["test"] = 1
fmt.Println(intMap) // panic: assignment to entry in nil map
}
当声明map不为其分配内存时候,intMap仅仅是个没有分配内存的空映射,map[string]int(nil)可以看到,map中的元素是nil,并不是0值,此时不能直接赋值,因为没内存。
2. new创建map
代码如下(示例):
package _3review
import (
"fmt"
"testing"
)
func TestNewMap(t *testing.T) {
nMap := new(map[string]int) // 声明map,为map分配内存!返回的是指向map的指针
fmt.Printf("nMap: %p %#v \n", &nMap, nMap) // nMap: 0xc0000a4048 &map[string]int(nil)
(*nMap)["test"] = 1 // (*nMap)解引用,为map添加元素,因为new函数创建map返回的是指针类型*hmap,需要通过解引用访问指针指向的值。
fmt.Println(nMap) // 依然是空指针,因为map里面元素对象是nil,并未初始化,所以无法赋值
}
使用new(map[string]int) 来创建map,new函数为map分配了内存,并返回指向该内存的指针。这种情况下,nMap 是一个指向 map[string]int 类型的指针变量。然而,new 函数返回的指针指向的内存仍然是未初始化的,因此 nMap 的值为指向一个空的映射的指针。
所以New创建引用类型,只为其分配内存,不能够初始化零值,无法直接使用。接下来看看make函数。
3. make创建map
func TestMakeMap(t *testing.T) {
m := make(map[string]int)
fmt.Printf("m: %p %#v \n", &m, m) //m: 0xc0000a4048 map[string]int{}
m["test"] = 1
fmt.Printf("m: %p %#v \n", &m, m) //m: 0xc000012058 map[string]int{"test":1}
// 结论:make不仅可以开辟一个内存,并且能给这个内存类型初始化零值
}
可以看到make函数为引用类型开辟了空间,并且初始化了零值,可以直接使用。
4. new和make一起创建map
func TestNewMakeMap(t *testing.T) {
var mv *map[string]int
fmt.Printf("mv: %p %#v \n", &mv, mv) //mv: 0xc0000a4048 (*map[string]int)(nil)
mv = new(map[string]int)
fmt.Printf("mv: %p %#v \n", &mv, mv) // mv: 0xc0000a4048 &map[string]int(nil)
*mv = make(map[string]int)
(*mv)["test"] = 1
fmt.Printf("mv: %p %#v \n", &mv, mv) // mv: 0xc0000a4048 &map[string]int{"test":1}
}
这个case意思是说,要想用new函数创建一个可用的引用类型,需要这么做:
- 先声明一个指针类型map;
- 用内置New(T)为这个指针类型的map分配内存;mv 的值为指向一个空的映射的指针;
- 使用make函数对指针指向的空映射做初始化操作。
如此就可以使用new来创建可用的引用类型,看上去有点复杂,所以才推荐使用make来创建引用类型。
总结
简单总结下,以及这种题怎么回答。
- new(T)可以为任意类型的数据分配内存,当使用new(T)创建引用类型时,引用类型初始化为nil,对于nil是不能被赋值的。这时需要使用make来初始化零值。
- make不仅可以开辟一个内存,还能给这个内存的类型初始化其零值。对于引用类型推荐使用make来创建。
make和new的区别?
- make和new都是golang用来分配内存的内建函数,且在堆上分配内存,make即分配内存,也初始化内存。new只是分配内存,并没有初始化内存。
- make返回的还是引用类型本身;而new返回的是指向类型的指针。
- make只能用来分配及初始化引用类型(map,slice,channel); 而new可以分配任意类型的数据。