Go: I get a struct field value without deferencing the pointer variable of the struct type, why?

huangapple go评论76阅读模式
英文:

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

huangapple
  • 本文由 发表于 2022年4月1日 16:42:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/71704139.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定