Go 语言开发者必备:深入解析 new 和 make 的使用差异
2022-11-14 03:07:48
new 和 make:内存分配的本质差异
在 Go 语言中,内存分配是构建程序的基础。new 和 make 作为两个重要的内存分配函数,发挥着不同的作用。了解它们的差异对于编写高效且健壮的代码至关重要。
分配内存的方式
new 使用 malloc 函数在堆上分配内存。堆是一个动态内存区域,允许在运行时动态分配和释放内存。new 返回指向新分配内存块的指针。
make 在栈上分配内存,栈是一个连续的内存区域,用于存储函数调用和局部变量。make 不使用指针,而是直接返回对新分配内存块的引用。
适用场景
new 适合创建结构体、接口和函数等复杂类型的对象。这些类型需要动态分配内存,因为它们的内存大小是未知的。
make 适合创建数组、切片、字典和通道等内置类型的对象。这些类型具有固定的大小,可以在编译时确定。
返回值
new 返回指向新创建对象的指针。指针可以为 nil ,表示对象尚未分配。
make 返回对新创建对象的引用。引用不能为 nil ,始终指向一个有效的对象。
性能差异
new 涉及系统调用,因此性能开销较大。
make 在栈上分配内存,不需要系统调用,因此性能开销较小。
使用场景
new
- 创建结构体对象:
type Person struct {
name string
age int
}
func main() {
person := new(Person)
person.name = "John Doe"
person.age = 30
}
- 创建接口对象:
type Speaker interface {
Speak()
}
func main() {
var speaker Speaker = new(Person)
speaker.Speak()
}
- 创建函数对象:
func main() {
add := func(a, b int) int {
return a + b
}
result := add(1, 2)
}
make
- 创建数组:
func main() {
array := make([]int, 5)
array[0] = 1
array[1] = 2
array[2] = 3
}
- 创建切片:
func main() {
slice := make([]int, 0, 5)
slice = append(slice, 1)
slice = append(slice, 2)
slice = append(slice, 3)
}
- 创建字典:
func main() {
dict := make(map[string]int)
dict["John Doe"] = 30
dict["Jane Doe"] = 25
}
- 创建通道:
func main() {
ch := make(chan int)
go func() {
ch <- 1
ch <- 2
ch <- 3
}()
for i := range ch {
fmt.Println(i)
}
}
结论
new 和 make 都是 Go 语言中用于分配内存的强大工具。通过理解它们的差异,您可以选择最适合特定情况的函数。这将帮助您创建高效、健壮且可维护的代码。
常见问题解答
1. 什么时候应该使用 ** new 而什么时候应该使用 ** make**?**
答: 使用 new 创建复杂类型的对象,这些对象的内存大小在编译时未知。使用 make 创建内置类型的对象,这些对象的内存大小在编译时已知。
2. ** new 和 ** make** 的返回值有什么区别?**
答: new 返回一个指针,而 make 返回一个引用。指针可以为 nil ,而引用不能为 nil 。
3. ** new 和 ** make** 的性能有什么差异?**
答: new 的性能开销比 make 大,因为 new 涉及系统调用。
4. 是否可以在栈上分配结构体对象?
答: 不可以。结构体对象必须在堆上分配,因为它们的内存大小在编译时未知。
5. 是否可以在堆上分配数组?
答: 可以。数组可以分配在堆上,但通常没有必要,因为数组的内存大小在编译时已知。