英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论