Golang make 函数
最后修改时间 2025 年 5 月 8 日
本教程将介绍如何在 Go 中使用内置的 make 函数。我们将通过实际示例介绍 slice、map 和 channel 的创建。
make 函数用于分配和初始化 slice、map 或 channel 类型的对象。与返回指针的 new 不同,make 返回一个已初始化并可直接使用的值。
在 Go 中,make 对于创建具有特定初始容量的复杂数据结构至关重要。它确保了内部状态的正确初始化。
使用 make 创建 slice
make 最简单的用法是创建具有指定长度和容量的 slice。此示例演示了基本的 slice 创建。
注意: 容量参数是可选的。
package main
import "fmt"
func main() {
// Create slice with length 3 and capacity 5
nums := make([]int, 3, 5)
fmt.Println("Slice:", nums)
fmt.Println("Length:", len(nums))
fmt.Println("Capacity:", cap(nums))
// Append elements within capacity
nums = append(nums, 4, 5)
fmt.Println("After append:", nums)
// Append beyond capacity
nums = append(nums, 6)
fmt.Println("After exceeding capacity:", nums)
}
Slice 以其长度的零值进行初始化。容量决定了底层数组何时需要重新分配。超出容量的追加会导致自动调整大小。
使用 make 创建 map
我们可以使用 make 创建具有初始容量的 map。此示例展示了 map 的创建和基本操作。
package main
import "fmt"
func main() {
// Create map with initial capacity
userAges := make(map[string]int, 10)
// Add elements
userAges["Alice"] = 25
userAges["Bob"] = 30
userAges["Charlie"] = 28
fmt.Println("User ages:", userAges)
// Check existence
if age, exists := userAges["Bob"]; exists {
fmt.Println("Bob's age:", age)
}
// Delete element
delete(userAges, "Charlie")
fmt.Println("After deletion:", userAges)
}
容量提示通过减少重新哈希来帮助优化 map 性能。Map 会动态增长,无论其初始容量如何。可以添加、检查和删除元素。
使用 make 创建带缓冲的 channel
make 用于创建具有指定缓冲区大小的 channel。此示例展示了带缓冲 channel 的操作。
package main
import "fmt"
func main() {
// Create buffered channel with capacity 3
messages := make(chan string, 3)
// Send messages without blocking
messages <- "first"
messages <- "second"
messages <- "third"
// Receive messages
fmt.Println(<-messages)
fmt.Println(<-messages)
fmt.Println(<-messages)
// Close channel
close(messages)
}
带缓冲的 channel 允许在不阻塞的情况下发送多个值。Channel 会持有值直到被接收。关闭是可选的,但在完成后建议关闭。
使用 make 和 copy 创建 slice
make 可以创建用于复制数据的 slice。此示例演示了高效的数据复制。
package main
import "fmt"
func main() {
original := []int{1, 2, 3, 4, 5}
// Create slice with exact needed capacity
copySlice := make([]int, len(original))
// Copy elements
copied := copy(copySlice, original)
fmt.Println("Original:", original)
fmt.Println("Copied:", copySlice)
fmt.Println("Elements copied:", copied)
// Modify copy
copySlice[0] = 100
fmt.Println("After modification:")
fmt.Println("Original:", original)
fmt.Println("Copied:", copySlice)
}
创建具有确切容量的 slice 可以避免不必要的分配。copy 函数返回复制的元素数量。修改副本不会影响原始数据。
使用 make 创建用于并发访问的 map
make 可以创建与同步原语一起使用的 map。此示例展示了线程安全的 map 访问。
package main
import (
"fmt"
"sync"
)
type SafeMap struct {
sync.RWMutex
data map[string]int
}
func NewSafeMap() *SafeMap {
return &SafeMap{
data: make(map[string]int),
}
}
func (sm *SafeMap) Set(key string, value int) {
sm.Lock()
defer sm.Unlock()
sm.data[key] = value
}
func (sm *SafeMap) Get(key string) (int, bool) {
sm.RLock()
defer sm.RUnlock()
val, exists := sm.data[key]
return val, exists
}
func main() {
sm := NewSafeMap()
var wg sync.WaitGroup
// Concurrent writes
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
key := fmt.Sprintf("key%d", i)
sm.Set(key, i)
}(i)
}
wg.Wait()
// Read values
for i := 0; i < 10; i++ {
key := fmt.Sprintf("key%d", i)
if val, exists := sm.Get(key); exists {
fmt.Printf("%s: %d\n", key, val)
}
}
}
SafeMap 包装器提供了对使用 make 创建的 map 的线程安全访问。互斥锁保护并发访问。这种模式在并发 Go 程序中很常见。
来源
本教程通过 slice、map 和 channel 创建的实际示例,介绍了 Go 中的 make 函数。