【本文正在参加金石计划附加挑战赛——第二期命题】
Go 语言是一种现代的、静态类型的编译型编程语言,旨在构建可扩展、并发且高效的软件。它提供了各种内置函数和特性,帮助开发者编写简洁高效的代码。其中包括 new() 和 make() 函数,乍一看它们可能相似,但在 Go 语言中有着不同的用途,对于内存分配和数据初始化至关重要。在这篇文章中我们将探讨 new() 和 make() 函数之间的区别,并了解何时以及如何有效地使用它们。
new() 和 make()
new() 和 make() 都是 Go 语言中用于内存分配的内置函数。然而,它们用于不同的数据类型和场景:
- new() 函数:用于为值类型(如整数、浮点数和结构体)分配内存,并返回指向新分配零值的指针。它接受一个参数,即类型,并返回指向该类型的指针。
- make() 函数:用于创建和初始化切片、映射和通道,这些是 Go 语言中的引用类型。它根据类型接受两个或三个参数,并返回一个已初始化(非零值)且可供使用的值。
new() 函数
new() 函数的语法非常简单,如下所示:
func new(Type) *Type
这里,Type 表示我们要为其分配内存的值的类型。下面看一个使用 new() 的示例。
在此示例中,我们使用 new() 为 Person 结构体创建一个新实例,然后使用指针为其字段赋值。
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
// 使用 new() 为 Person 结构体分配内存
p := new(Person)
fmt.Printf("%T\n", p)
// 使用指针访问结构体字段
p.Name = "Alice"
p.Age = 30
// 显示值
fmt.Println("Name:", p.Name)
fmt.Println("Age:", p.Age)
}
输出将是:
*main.Person
Name: Alice
Age: 30
make() 函数
make() 函数的语法取决于它所用于的类型。
- 对于切片:
func make([]Type, len, cap) []Type
- Type:切片将容纳的元素类型。
- len:切片的初始长度。
- cap:切片的容量,这是可选的,用于指定底层数组的容量。如果未提供,默认为与长度相同。
下面是一个使用 make() 创建切片的示例:
package main
import "fmt"
func main() {
// 使用 make() 创建一个整数切片
numbers := make([]int, 5, 10)
// 显示切片的长度、容量和值
fmt.Println("Length:", len(numbers))
fmt.Println("Capacity:", cap(numbers))
fmt.Println("Values:", numbers)
// 使用 make() 创建一个整数切片(不指定容量)
numbersWithoutOptional := make([]int, 5)
// 显示切片的长度、容量和值
fmt.Println("Length:", len(numbersWithoutOptional))
fmt.Println("Capacity:", cap(numbersWithoutOptional))
fmt.Println("Values:", numbersWithoutOptional)
}
输出将是:
Length: 5
Capacity: 10
Values: [0 0 0 0 0]
Length: 5
Capacity: 5
Values: [0 0 0 0 0]
- 对于映射:
func make(map[KeyType]ValueType, initialCapacity int) map[KeyType]ValueType
- KeyType:映射中键的类型。
- ValueType:与键关联的值的类型。
- initialCapacity:映射的初始容量。这是可选的,但在预先知道元素数量时可用于优化性能。
下面是一个使用 make() 创建映射的示例:
package main
import "fmt"
func main() {
// 使用 make() 创建一个字符串键和整数值的映射
scores := make(map[string]int)
// 向映射中添加值
scores["Alice"] = 95
scores["Bob"] = 87
// 显示映射
fmt.Println("Scores:", scores)
}
输出将是:
Scores: map[Alice:95 Bob:87]
- 对于通道:
func make(chan Type, capacity int) chan Type
- Type:可以通过通道发送和接收的值的类型。
- capacity:通道的缓冲区大小。如果设置为 0,通道是无缓冲的。
下面是一个使用 make() 创建通道的示例:
package main
import (
"fmt"
"time"
)
func main() {
// 使用 make() 创建一个无缓冲的整数通道
ch := make(chan int)
// 使用 goroutine 向通道发送数据
go func() {
for i := 1; i <= 5; i++ {
ch <- i
time.Sleep(time.Second) // 模拟在发送下一个值之前进行一些工作
}
close(ch)
}()
// 从通道接收数据
for num := range ch {
fmt.Println("Received:", num)
}
}
输出将是:
Received: 1
Received: 2
Received: 3
Received: 4
Received: 5
结论
- 使用 new() 为值类型分配内存并获取指向零值的指针。
- 使用 make() 创建和初始化切片、映射和通道(引用类型),指定它们的类型和初始容量。