Go中make创建slice可指定长度和容量,影响内存分配;而创建map仅初始化结构,容量为提示,核心差异在于内存管理与初始化行为。

在Go语言中,动态创建slice和map对象,核心在于理解它们在内存分配和数据结构上的差异。简单来说,slice的动态性体现在其长度和容量的可变性,而map则是在运行时根据需要增删键值对。两者都依赖Go的内置函数
make
在Go语言里,动态创建
slice
map
对于
slice
make
make([]int, 0, 10)
int
make([]string, 5)
var mySlice []byte
append
append
而
map
make(map[string]int)
string
int
map
m["key"] = value
delete(m, "key")
map
make
make(map[string]int, 100)
立即学习“go语言免费学习笔记(深入)”;
package main
import (
"fmt"
)
func main() {
// 动态创建slice示例
fmt.Println("--- Slice 示例 ---")
// 方式一:使用 make 预分配容量,长度为0
dynamicInts := make([]int, 0, 5)
fmt.Printf("初始 slice: %v, 长度: %d, 容量: %d\n", dynamicInts, len(dynamicInts), cap(dynamicInts))
// 添加元素,容量足够时不会重新分配
dynamicInts = append(dynamicInts, 10, 20, 30)
fmt.Printf("添加元素后: %v, 长度: %d, 容量: %d\n", dynamicInts, len(dynamicInts), cap(dynamicInts))
// 添加更多元素,可能触发扩容
dynamicInts = append(dynamicInts, 40, 50, 60, 70) // 此时容量不足,会扩容
fmt.Printf("再次添加元素后: %v, 长度: %d, 容量: %d\n", dynamicInts, len(dynamicInts), cap(dynamicInts))
// 方式二:声明一个 nil slice,让 append 自动处理
var anotherStrings []string
fmt.Printf("初始 nil slice: %v, 长度: %d, 容量: %d\n", anotherStrings, len(anotherStrings), cap(anotherStrings))
anotherStrings = append(anotherStrings, "hello", "world")
fmt.Printf("添加元素后: %v, 长度: %d, 容量: %d\n", anotherStrings, len(anotherStrings), cap(anotherStrings))
// 动态创建map示例
fmt.Println("\n--- Map 示例 ---")
// 方式一:使用 make 创建空 map
dynamicUsers := make(map[string]int) // string -> int
fmt.Printf("初始 map: %v, 长度: %d\n", dynamicUsers, len(dynamicUsers))
// 添加元素
dynamicUsers["Alice"] = 30
dynamicUsers["Bob"] = 25
fmt.Printf("添加元素后: %v, 长度: %d\n", dynamicUsers, len(dynamicUsers))
// 更新元素
dynamicUsers["Alice"] = 31
fmt.Printf("更新 Alice 后: %v, 长度: %d\n", dynamicUsers, len(dynamicUsers))
// 检查元素是否存在
age, ok := dynamicUsers["Bob"]
if ok {
fmt.Printf("Bob 的年龄是: %d\n", age)
}
// 删除元素
delete(dynamicUsers, "Bob")
fmt.Printf("删除 Bob 后: %v, 长度: %d\n", dynamicUsers, len(dynamicUsers))
// 方式二:使用字面量初始化 map
config := map[string]string{
"host": "localhost",
"port": "8080",
}
fmt.Printf("字面量初始化 map: %v, 长度: %d\n", config, len(config))
}
make
这是一个很棒的问题,因为
make
slice
map
make
最核心的区别在于,
make
slice
长度(length)
容量(capacity)
长度
容量
make([]int, 5, 10)
int
slice[0]
slice[4]
slice[5]
append
而
make
map
make(map[string]int)
make
map
make
make(map[string]int, 100)
slice
length
map
len(myMap)
简单来说,
slice
make
map
make
向Go
slice
append
append
当一个
slice
append
slice
为了高效地添加元素,关键在于减少扩容的次数。
本书全面介绍PHP脚本语言和MySOL数据库这两种目前最流行的开源软件,主要包括PHP和MySQL基本概念、PHP扩展与应用库、日期和时间功能、PHP数据对象扩展、PHP的mysqli扩展、MySQL 5的存储例程、解发器和视图等。本书帮助读者学习PHP编程语言和MySQL数据库服务器的最佳实践,了解如何创建数据库驱动的动态Web应用程序。
385
预分配容量: 如果你对最终的
slice
slice
make
mySlice := make([]MyStruct, 0, 100)
append
// 示例:预分配容量
const expectedSize = 10000
data := make([]int, 0, expectedSize)
for i := 0; i < expectedSize; i++ {
data = append(data, i)
}
// 此时,data 的容量很可能就是 expectedSize,没有或很少发生扩容
fmt.Printf("预分配容量后,长度: %d, 容量: %d\n", len(data), cap(data))避免在循环内频繁创建新slice
slice[i:j]
了解扩容策略: Go语言的
append
当然,如果完全无法预估大小,或者数据量非常小,那么直接使用
var s []T
append
Go语言的
map
map
panic
fatal error: concurrent map writes
核心问题在于:Go内置的map
这意味着,当多个Goroutine同时对同一个
map
map
那么,我们该如何处理
map
使用sync.RWMutex
sync.RWMutex
map
map
RLock()
RUnlock()
Lock()
Unlock()
package main
import (
"fmt"
"sync"
"time"
)
type SafeMap struct {
mu 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.mu.Lock()
defer sm.mu.Unlock()
sm.data[key] = value
}
func (sm *SafeMap) Get(key string) (int, bool) {
sm.mu.RLock()
defer sm.mu.RUnlock()
val, ok := sm.data[key]
return val, ok
}
func main() {
safeMap := NewSafeMap()
// 多个 Goroutine 并发写入
for i := 0; i < 100; i++ {
go func(id int) {
safeMap.Set(fmt.Sprintf("key%d", id), id)
}(i)
}
// 等待一段时间,确保写入完成
time.Sleep(100 * time.Millisecond)
// 多个 Goroutine 并发读取
for i := 0; i < 10; i++ {
go func(id int) {
val, ok := safeMap.Get(fmt.Sprintf("key%d", id*10))
if ok {
fmt.Printf("读取 key%d: %d\n", id*10, val)
}
}(i)
}
time.Sleep(100 * time.Millisecond) // 等待读取完成
}使用sync.Map
sync.Map
map
RWMutex
map
map
Store
Load
LoadOrStore
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var concurrentMap sync.Map // 声明一个 sync.Map
// 多个 Goroutine 并发写入
for i := 0; i < 100; i++ {
go func(id int) {
concurrentMap.Store(fmt.Sprintf("key%d", id), id)
}(i)
}
time.Sleep(100 * time.Millisecond)
// 多个 Goroutine 并发读取
for i := 0; i < 10; i++ {
go func(id int) {
if val, ok := concurrentMap.Load(fmt.Sprintf("key%d", id*10)); ok {
fmt.Printf("读取 key%d: %v\n", id*10, val)
}
}(i)
}
time.Sleep(100 * time.Millisecond)
}选择哪种方式取决于具体的应用场景和性能需求。如果并发访问模式复杂,或者对性能有极致要求,
sync.Map
sync.RWMutex
map
以上就是Golang动态创建slice与map对象示例的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号