英文:
Go: I get a struct field value without deferencing the pointer variable of the struct type, why?
问题
// config/config.go
package config
import (
"github.com/spf13/viper"
)
type Config struct {
Database *DatabaseConfig `mapstructure:"database"`
Server *ServerConfig `mapstructure:"server"`
Redis *RedisConfig `mapstructure:"redis"`
Jwt *JwtConfig `mapstructure:"jwt"`
Smtp *SmtpConfig `mapstructure:"smtp"`
}
func New() (config *Config) {
viper.AddConfigPath(".")
viper.SetConfigName("config")
if err := viper.ReadInConfig(); err != nil {
panic(err)
}
if err := viper.Unmarshal(&config); err != nil {
panic(err)
}
return
}
// db/connection.go
package db
import (
"fmt"
"my.project/config"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func New(config *config.DatabaseConfig) *gorm.DB {
dsn := fmt.Sprintf(
"%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
config.Username, config.Password, config.Host, config.Port, config.Database,
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println("Failed to connect to database")
panic(err)
}
RunMigrations(db)
return db
}
// main.go
package main
import (
"fmt"
"my.project/config"
)
func main() {
config := config.New()
fmt.Println(config.Database)
db := db.New(config.Database)
if db == nil {
panic("Failed to connect to database")
}
}
在上面的代码片段中,config 是指向 Config 类型变量的指针(显然是从 config.New() 的返回类型推断出来的),但是 config.Database 似乎是一个值(而不是引用)。
我原以为 config.Database 会是一个引用,但实际上不是(我尝试打印它们,config 明显是一个引用,而 config.Database 是一个值)。
有人可以帮助我理解为什么吗?非常感谢!
英文:
// config/config.go
package config
import (
"github.com/spf13/viper"
)
type Config struct {
Database DatabaseConfig `mapstructure:"database"`
Server ServerConfig `mapstructure:"server"`
Redis RedisConfig `mapstructure:"redis"`
Jwt JwtConfig `mapstructure:"jwt"`
Smtp SmtpConfig `mapstructure:"smtp"`
}
func New() (config *Config) {
viper.AddConfigPath(".")
viper.SetConfigName("config")
if err := viper.ReadInConfig(); err != nil {
panic(err)
}
if err := viper.Unmarshal(&config); err != nil {
panic(err)
}
return
}
// db/connection.go
package db
import (
"fmt"
"my.project/config"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func New(config config.DatabaseConfig) *gorm.DB {
dsn := fmt.Sprintf(
"%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
config.Username, config.Password, config.Host, config.Port, config.Database,
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println("Failed to connect to database")
panic(err)
}
RunMigrations(db)
return db
}
// main.go
package main
import (
"fmt"
"my.project/config"
)
func main() {
config := config.New()
fmt.Println(config.Database)
db := db.New(config.Database)
if db == nil {
panic("Failed to connect to database")
}
}
In the above snippets, config is a pointer to a Config type variable (apparently from the return type of config.New()), but config.Database seems to be a value (not a reference).
I assumed config.Database would be a reference either but it's not (I tried to print out them, config was definitely a reference and config.Database was a value).
Can anyone help me to understand why? Thank you in advance!
答案1
得分: -1
原来,这源于一项语言设计决策。实际上,如果你使用(*config).Database,是完全有效的。然而,Go语言的设计者认为这种表示方式很繁琐,所以语言允许我们写成config.Database,而不需要显式解引用。这些指向结构体的指针甚至有自己的名称——"结构体指针",它们会自动解引用。这里有一个关于"自动解引用"的很好的解释:https://stackoverflow.com/questions/13533681/when-do-gos-pointers-dereference-themselves
英文:
It turned out that this was originated from one of the language design decisions. In fact, if you use (*config).Database, it is absolutely valid. However, the makers of Go deemed this notation cumbersome, so the language permits us to write config.Database,
without an explicit dereference. These pointers to structs even have their own name struct pointers and they are automatically dereferenced. Here's another superb explanation for "auto-deferencing": https://stackoverflow.com/questions/13533681/when-do-gos-pointers-dereference-themselves
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论