golang var、:=、new、make区别及使用

​ go里面的几大变量“类型”(不严谨,只是个人在使用的时候常用到的结构的一个划分)

  • (1) 值类型: intstringstruct
  • (2) 引用类型:主要是 map, slice,chan 这三个引用(make创建内存的)
  • (3)指针类型:*int64*struct

var vs :=

​ 对于值类型的变量,我们通过var 声明(包括结构体),系统会默认为他分配内存空间,并赋该类型的零值。

如下,我们声明一个int类型变量i,输出为0。

1
2
var i int
fmt.Println(i) // i = 0 (类型零值)

var:=之间实际上存在差异,采用:=允许重新声明变量

与常规变量声明不同,:=声明可以重新声明变量,前提是它们最初在同一块中以相同类型声明,并且至少有一个非空白变量是新的。因此,重新声明只能出现在多变量短声明中。

重新声明不引入新变量;它只是为原始值分配一个新值。

1
2
3
4
field1, offset := nextField(str, 0)
field2, offset := nextField(str, offset)  // 重新声明偏移量(可重入)

a, a := 1, 2                              // 非法:如果在别处声明了 a,则双重声明 a 或没有新变量

所以我会说:=运算符不是纯粹的声明,而是更像声明和分配。不允许在顶层重新声明,因此也不允许短声明。另一个原因可能是语法简单。type在 Go 中,所有顶级表单都以varfunc 开头。

建议:重复声明的变量用 :=,比如 err 的声明,使用的值或全局变量(不推荐大量使用)用 var, 如 var fields []string

new函数

来看一下new函数的签名:

1
func new(Type)*Type

​ 它只接受一个参数,这个参数是一个类型,分配好内存后,返回一个指向该类型内存地址的指针。同时把分配的内存置为零,也就是类型的零值。但是实际在工程使用中,通常是直接声明指针使用,不需要 new 操作。

如果我们声明一个指针类型的变量,系统不会为他分配内存,默认就是nil。此时如果你想直接使用,那么系统会抛异常。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var j *int
fmt.Println(j)
*j = 10  //invalid memory address or nil pointer dereference

// 也就是说,空指针还没有内存分配,是不能使用的。那么要想使用,此时就需要new出场啦。
var j *int
j = new(int)  // 让j里面的内容指向一块分配好的内存地址,地址里面设置int的零值:0
fmt.Println(j)
fmt.Println(*j)
*j = 10
fmt.Println(*j)
// 声明指针类型变量后,通过new为他分配内存,有了内存空间,这个变量就可以自由的使用了。

Make函数

makenew不同,make 用于 map, slice,chan 的内存创建,因为他们三个是引用类型,直接返回这三个类型本身。

make签名是:

1
func make(t Type, size ...IntegerType) Type

make 是分配内存并初始化,初始化并不是置为零值(而是将地址空间的值二进制为都设置为0)

与new一样,它的第一个参数也是一个类型,但是不一样的是,make返回的是传入的类型,而不是指针!

1
2
3
4
5
6
7
var c chan int //声明管道类型变量c,此时c还是nil,不可用

fmt.Printf("%#v \\n",c) //(chan int)(nil)

c = make(chan int)

fmt.Printf("%#v", c) //(chan int)(0xc000062060)

声明管道类型变量c,此时c还是nil,不可用;通过make来分配内存并初始化,c就获得了内存可以使用了。所以,我们在使用map, slice,chan 的时候,需要先对他们用make初始化,然后在进行操作。

总结

  • new make都是Go语言的两个内建函数,用于分配内存
  • new 一般用来返回指针类型(一般不用),make返回引用类型(map, slice,chan 这三个引用)
  • var声明的 基本类型和struct这种已经分配了内存,并且赋零值了。

参考链接