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
函数。