Table of Contents
new
new 的主要特性
首先 new 是内建函数,你可以从 http://golang.org/pkg/builtin/#new 这儿看到它,它的定义也很简单:
func new(Type) *Type
官方文档对于它的描述是:
内建函数 new 用来分配内存,它的第一个参数是一个类型,不是一个值,它的返回值是一个指向新分配类型零值的指针
根据这段描述,我们可以自己实现一个类似 new 的功能:
func newInt() *int { var i int return &i } someInt := newInt()
我们这个函数的功能跟 someInt := new(int) 一模一样。所以在我们自己定义 new 开头的函数时,出于约定也应该返回类型的指针。
new(T) 为每个新的类型T分配一片内存,初始化为 0 并且返回类型为*T的内存地址:这种方法 返回一个指向类型为 T,值为 0 的地址的指针,它适用于值类型如数组和结构体;它相当于 &T{}。
make(T) 返回一个类型为 T 的初始值,它只适用于3种内建的引用类型:slice、map 和 channel。
换言之,new 函数分配内存,make 函数初始化;下图给出了区别:
通过实验,可以更直观的查看两者之间的区别
Go 语言中 new 和 make 都是内置函数,用于内存的分配,本文主要简述两者使用上的异同与特性。
例子一:
func main() { var i *int *i = 1 fmt.Println(*i) }
上面的程序并不会打印1,而会抛 panic 异常,因为i是一个引用类型,需要给它分配内存空间,通俗来说就是指针(内存地址)需要指向一片内存空间才有意义。
为 i 分配内存:
func main() { var i *int i = new(int) *i = 1 fmt.Println(*i) }
用 new 内置函数为 i 分配内存空间,并返回该内存空间的地址,即指针,new 函数格式如下:
func new(Type) *Type
可知,new 为每个类型分配一片内存空间,初始化为 0 并返回该内存空间的地址。
new 的内存分配示意图:
其实要说明一点的就是,new 不常用,我们常常会通过结构体的字面量达到 new 的效果,而且这样写也比较优雅:
man := &People{Name: "zhangchenghui", Age: 18, Sex: "男"}
例子二:
package main import "fmt" // new函数用来分配内存,主要分配值类型,比如int、float32、struct等,返回的是指针 func main() { num1 := 100 add(&num1) fmt.Printf("num1的类型是%T,num1的值为%v,num1的地址是%v %d\n", num1, num1, &num1, num1) //结果---num1的类型是int,num1的值为100,num1的地址是0xc042052058 //内存分配说明: //内存里会开辟一个空间,num1指向这个空间,这个空间了里放了值100,那么num1的地址就是这块空间的地址 num2 := new(int) *num2 = 200 add(num2) fmt.Printf("num2的类型是%T,num2的值为%v,num2的地址是%v %d\n", num2, num2, &num2, *num2) //结果---num2的类型是*int,num2的值为0xc0420520a0,num2的地址是0xc042072020 //内存分配说明: //num2本身是指针类型,num2会指向一个空间,但是这个空间里的值是一个地址,就是0xc0420520a0,但是这个 //空间本身也有一个地址,地址就是0xc042072020,而0xc042072020这个地址默认情况的值是个0,因为没有赋值 //进一步说明 fmt.Printf("num2的类型是%T,num2的值为%v,num2的地址是%v,num2这个指针指向的值是%v", num2, num2, &num2, *num2) //结果---num2的类型是*int,num2的值为0xc0420520a0,num2的地址是0xc042072020,num2这个指针指向的值是0 } func add(i *int) { *i = *i + 56 }
例子三:
p := new([]int) //p == nil; with len and cap 0 fmt.Println(p) v := make([]int, 10, 50) // v is initialed with len 10, cap 50 fmt.Println(v) /*********Output**************** &[] [0 0 0 0 0 0 0 0 0 0] *********************************/ //(*p)[0] = 18 // panic: runtime error: index out of range // because p is a nil pointer, with len and cap 0 *p = append(*p, 2, 3, 4) v[1] = 18 // ok v[0] = 218 // ok fmt.Printf("%T %d %d %d\n", p, *p, len(*p), len(*p)) fmt.Printf("%T %d %d %d\n", v, v, len(v), len(v))
make
make 的主要特性
make 也是内建函数,你可以从 http://golang.org/pkg/builtin/#make 这儿看到它,它的定义比 new 多了一个参数,返回值也不同:
func make(Type, size IntegerType) Type
官方文档对于它的描述是:
内建函数 make 用来为 slice,map 或 chan 类型分配内存和初始化一个对象(注意:只能用在这三种类型上),跟 new 类似,第一个参数也是一个类型而不是一个值,跟 new 不同的是,make 返回类型的引用而不是指针,而返回值也依赖于具体传入的类型,具体说明如下:
Slice: 第二个参数 size 指定了它的长度,它的容量和长度相同。 你可以传入第三个参数来指定不同的容量值,但必须不能比长度值小。 比如 make([]int, 0, 10) Map: 根据 size 大小来初始化分配内存,不过分配后的 map 长度为 0,如果 size 被忽略了,那么会在初始化分配内存时分配一个小尺寸的内存 Channel: 管道缓冲区依据缓冲区容量被初始化。如果容量为 0 或者忽略容量,管道是没有缓冲区的
make 也是分配内存分配,但是仅限 chan、map、slice 的内存创建,并返回其类型的引用,这一点很重要, chan、map、slice 其本身已经是引用类型了,所以make不需要再返回其指针,引用类型的本质就是指针!例如:
type i *int;
如上,i 就是一个自定义的引用类型,其类型是一个 int 类型的指针。
Make 内置函数格式:
func make(t Type, size ...IntegerType) Type
make 的内存分配示意图:
总结
new 的作用是初始化一个指向类型的指针(*T),make 的作用是为 slice,map 或 chan 初始化并返回引用(T)。
评论前必须登录!
注册