GO结构体与指针【1】什么时候用指针

请问什么时候用指针什么时候用实体,例如多层级的配置信息,配置结构体载入做成接收者可以吗?

这是一个非常经典的问题。在 Go 中,配置信息(Config)通常建议使用指针或在初始化后作为全局只读变量。

1. 结构体字段建议:使用实体还是指针?

结论:结构体内部字段建议用实体,但对外传递和全局变量建议用指针。

  • 配置项(字段): 像 RedisConfig 这种小型结构体,直接用实体(Value)更好。它在内存中是连续的,对垃圾回收(GC)更友好。
  • 总配置(App): 建议将 var App Config 改为 var App *Config。

2. 核心优化方案:修改 Load 模式

你目前的 Load 方法是在接收器上调用并返回新对象,这在逻辑上有点绕。更高效、更惯用的做法是直接初始化并返回指针。

修改 pkg\config\config.go

复制代码
package config

// 将全局变量设为指针
var App *Config

type Config struct {
	Server ServerConfig
	DB     map[string]DbConfig
	Redis  RedisConfig
	Logger LoggerConfig
}

// 改为函数,直接返回指针
func NewConfig() *Config {
	// 直接初始化,避免多次拷贝
	return &Config{
		Server: LoadServerConfig(), // 假设你改成了普通函数
		DB: map[string]DbConfig{
			"biz":    LoadDbConfig("biz"),
			"report": LoadDbConfig("report"),
		},
		Redis:  LoadRedisConfig(),
		Logger: LoadLoggerConfig(),
	}
}

修改 pkg\config\redis.go

复制代码
// 建议改为普通函数,返回实体值即可
func LoadRedisConfig() RedisConfig {
	return RedisConfig{
		Host:     getEnv("REDIS_HOST", "localhost"),
		Port:     GetEnvInt("REDIS_PORT", 6379),
		Password: getEnv("REDIS_PASSWORD", "123qwe"),
		DB:       GetEnvInt("REDIS_DB", 1),
	}
}

3. 为什么这样更高效?

  1. 减少拷贝: 你原来的 config.App = config.App.LoadAll() 会在栈上创建临时对象,然后再赋值给全局变量,产生两次内存拷贝。使用指针(*Config)后,全局变量只存储一个 8 字节的地址。
  2. 避免副作用: 你的 Load 方法使用了指针接收器 (r *RedisConfig) 但内部没用到 r,这容易产生误导。改为普通的 New 或 Load 函数更清晰。
  3. 并发安全: 配置通常在 main 启动时一次性加载。一旦加载完成,全局指针指向的内存就不再变动,多协程并发读取 App.Redis.Host 是非常高效且安全的。

4. 改进后的 main 函数

复制代码
func main() {
	_ = godotenv.Load()
	
	// 初始化全局指针
	config.App = config.NewConfig()
    
	// 使用时很方便:config.App.Redis.Host
}
相关推荐
FungLeo3 小时前
成为全栈·Go 后端篇·重写之前先锁基线:契约、Node 版本与行为清单
golang·node.js·go·openapi·契约测试·成为全栈
小满zs13 小时前
Go语言第十七章(反射)
后端·go
小满zs13 小时前
Go语言第十五章(JSON序列化)
后端·go
小满zs13 小时前
Go语言第十六章(自定义类型)
后端·go
w-w0w-w14 小时前
Go语言学习day1
go
FungLeo1 天前
成为全栈·Go 后端篇·契约一致性与差分测试:两套实现如何互相校验
golang·node.js·go·合约测试·差分测试·成为全栈·api兼容
vipxieliang1 天前
Go 1.25 Green Tea GC 深度解析:以页为单位的垃圾回收新范式
go
孔令飞1 天前
AI 时代岗位调研分析:调研了近3000份AI岗位描述,分享下调研结果
云原生·go·ai编程
我不会起名字3221 天前
Redis 从 0 到 1(十二):先删缓存还是先更新库?4 种方案的 Go 并发实测
redis·go·并发·延迟双删·缓存一致性
FungLeo2 天前
成为全栈·Go 后端篇·用 Go 重写分层架构:领域包、装配根与最小抽象
golang·go·领域驱动设计·gorm·分层架构·成为全栈