Golang依赖注入 - 应该使用值传递还是指针/引用传递?
Golang依赖注入 - 应该使用值传递还是指针/引用传递? 由于我没有找到与这个特定问题相关的太多资料,我直接在这里提问:
假设我们有一个包含存储、数据库连接和一些服务等的应用程序。由于我之前使用PHP,目前我通过指针注入这些依赖项,例如:
服务 <- 存储 <- 数据库连接
但这真的是在Go中应该采用的方式吗?还是通过值注入这些依赖项更为合适?
我的观点是,"按值传递"意味着会创建一个副本。我认为这对于数据库连接或类似服务来说没有意义。
更多关于Golang依赖注入 - 应该使用值传递还是指针/引用传递?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我知道区别。但这与状态变化的对象无关——而是关于在应用程序启动时创建的对象图。
但我不知道对此是否有任何约定。
按值传递会创建一个副本。参考以下示例:
package main
import (
"fmt"
)
type Service struct {
counter int
}
func (service *Service) inc() {
service.counter = service.counter + 1
}
func manipulate(service Service) Service {
service.inc()
return service
}
func main() {
s := Service{}
s.inc()
s.inc()
fmt.Println("s", s)
t := manipulate(s)
fmt.Println("s", s) // 仍然计数为2!
fmt.Println("t", t) // 是副本且计数为3!
}
输出:
s { 2}
s { 2}
t { 3}
始终使用指针。
对于较小的数据结构,你可以按值传递,但对于较大的数据结构这样效率不高,因此应该通过引用传递。数据库连接肯定要作为引用传递。如果这与HTTP服务器相关,以下内容可能会很有趣:
七年后我如何编写Go HTTP服务——Statuscode——Medium
我从r59版本就开始编写Go(书面写作时称为Golang)——那是1.0之前的版本
阅读时间:6分钟
在Go语言中,依赖注入通常应该使用指针传递,而不是值传递。这主要是出于性能和状态一致性的考虑。
为什么推荐指针传递
1. 避免不必要的拷贝
依赖项(如数据库连接、存储服务等)通常包含大量数据或资源,值传递会导致完整的结构体拷贝,造成性能开销。
type Database struct {
conn *sql.DB
config Config
// 可能还有其他大量字段
}
type Storage struct {
db *Database
cache map[string]interface{}
}
type Service struct {
storage *Storage
}
// 使用指针注入
func NewService(storage *Storage) *Service {
return &Service{storage: storage}
}
2. 确保状态一致性
当多个组件共享同一个依赖时,使用指针可以确保它们操作的是同一个实例,状态变更对所有使用者可见。
type Config struct {
Timeout int
}
type Database struct {
config *Config
}
type ServiceA struct {
db *Database
}
type ServiceB struct {
db *Database
}
// 所有服务共享同一个配置实例
config := &Config{Timeout: 30}
db := &Database{config: config}
serviceA := &ServiceA{db: db}
serviceB := &ServiceB{db: db}
// 修改配置对所有服务生效
db.config.Timeout = 60
3. 支持接口实现
依赖注入通常结合接口使用,而接口值本身包含指向具体实现的指针。
type UserRepository interface {
FindByID(id int) (*User, error)
}
type MySQLUserRepository struct {
db *sql.DB
}
type UserService struct {
repo UserRepository // 接口值,内部包含指针
}
func NewUserService(repo UserRepository) *UserService {
return &UserService{repo: repo}
}
值传递的适用场景
值传递仅适用于小型、不可变的数据结构:
type Config struct {
Port int
Timeout int
}
// 对于小型配置,值传递也可以接受
type Server struct {
config Config
}
总结
在Go语言的依赖注入中,对于服务、存储、数据库连接等有状态的依赖项,应该使用指针传递。这符合Go语言的惯用法,能够提供更好的性能和确保状态一致性。


