new
和 make
1、执行报错
- 执行下面的代码会引发 panic,为什么呢?
- 在 Go 语言中对于引用类型的变量,我们在使用的时候不仅要声明它,还要为它分配内存空间,否则我们的值就没办法存储。
- 而对于值类型的声明不需要分配内存空间,是因为它们在声明的时候已经默认分配好了内存空间。
- 要分配内存,就引出来今天的
new
和make
。 - Go 语言中
new
和make
是内建的两个函数,主要用来分配内存。
//以下代码报错
package main
import "fmt"
func main() {
var userinfo map[string]string
userinfo["username"] = "张三"
fmt.Println(userinfo)
}
/*
panic: assignment to entry in nil map
*/
make
和new
比较
new
和make
是两个内置函数,主要用来创建并分配类型的内存。make
和new
区别make
关键字的作用是创建于slice
、map
和channel
等内置的数据结构new
的作用是为类型申请一片内存空间,并返回指向这片内存的指针
package main
import "fmt"
func main() {
a := make([]int, 3, 10) // 切片长度为 1,预留空间长度为 10
a = append(a, 1)
fmt.Printf("%v--%T \n", a, a) // [0 0 0]--[]int 值----切片本身
var b = new([]int)
//b = b.append(b,2) // 返回的是内存指针,所以不能直接 append
*b = append(*b, 3) // 必须通过 * 指针取值,才能进行 append 添加
fmt.Printf("%v--%T", b, b) // &[]--*[]string 内存的指针---内存指针
}
new
函数
一:系统默认的数据类型,分配空间
package main
import "fmt"
func main() { // 1.new实例化int
age := new(int)
*age = 1
// 2.new实例化切片
li := new([]int)
*li = append(*li, 1)
// 3.实例化map
userinfo := new(map[string]string)
*userinfo = map[string]string{}
(*userinfo)["username"] = "张三"
fmt.Println(userinfo) // &map[username:张三]
}
二:自定义类型使用 new
函数来分配空间
package main
import "fmt"
func main() {
var s *Student
s = new(Student) //分配空间
s.name = "zhangsan"
fmt.Println(s) // &{zhangsan 0}
}
type Student struct {
name string
age int
}
make
函数
make
也是用于内存分配的,但是和new
不同,它只用于chan
、map
以及slice
的内存创建- 而且它返回的类型就是这三个类型本身,而不是他们的指针类型
- 因为这三种类型就是引用类型,所以就没有必要返回他们的指针了
package main
import "fmt"
func main() {
a := make([]int, 3, 10) // 切片长度为 1,预留空间长度为 10
b := make(map[string]string)
c := make(chan int, 1)
fmt.Println(a, b, c) // [0 0 0] map[] 0xc0000180e0
}
- 当我们为
slice
分配内存的时候,应当尽量预估到slice
可能的最大长度 - 通过给
make
传第三个参数的方式来给slice
预留好内存空间 - 这样可以避免二次分配内存带来的开销,大大提高程序的性能。