在Go语言中使用viper库时,为什么需要传递指针的地址而不是指针本身?

问题探讨:在go语言中使用viper库时的指针传参问题

在编写go程序时,经常会遇到关于指针和内存地址的问题。尤其是在使用第三方库如viper时,指针的使用更加复杂。本文将通过一个具体的例子,详细解释在go语言中使用viper库时的指针传参问题。

首先,我们来看一下代码示例:

setting模块:

type setting struct {     vp *viper.viper }  func newsetting() (*setting, error) {     vp := viper.new()     vp.setconfigname("config")     vp.addconfigpath("configs/")     vp.setconfigtype("yaml")     err := vp.readinconfig()     if err != nil {         return nil, err     }      return &setting{vp: vp}, nil }

section模块:

立即学习go语言免费学习笔记(深入)”;

type serversettings struct {     runmode      string     httpport     string     readtimeout  time.duration     writetimeout time.duration }  func (s *setting) readsection(k string, v interface{}) error {     err := s.vp.unmarshalkey(k, v)     if err != nil {         return err     }      return nil }

global模块:

var serversetting *setting.serversettings

main模块:

setting, err := setting.newsetting()  setting.readsection("server", &global.serversetting)

在上述代码中,如果我们在main模块中将第二行修改为setting.readsection(“server”, global.serversetting),程序会报错result must be addressable (a pointer)。为什么会出现这个问题呢?

首先需要明确的是,虽然global.serversetting是一个指针,但这并不意味着它可以被直接传递给readsection函数。我们需要传递的是指针的地址,而不是指针本身。

要理解这一点,我们需要深入viper库的源码。在viper库的newdecoder函数中,有这样一段代码:

// newdecoder returns a new decoder for the given configuration. once // a decoder has been returned, the same configuration must not be used // again. func newdecoder(config *decoderconfig) (*decoder, error) {     val := reflect.valueof(config.result)     if val.kind() != reflect.ptr {         return nil, errors.new("result must be a pointer")     }      val = val.elem()     if !val.canaddr() {         return nil, errors.new("result must be addressable (a pointer)")     } }

这段代码说明了问题的关键:传递的参数不仅需要是一个指针,还必须是可以被寻址的(addressable)。当我们传递一个结构体的指针时,它并不能被寻址,因此会报错。

为了进一步理解这个问题,我们可以看一个简单的例子:

package main  import (     "fmt"     "reflect" )  var a *db  type db struct { }  func main() {     val := reflect.valueof(a)     val = val.elem()     fmt.println(val.canaddr())      val = reflect.valueof(&a)     val = val.elem()     fmt.println(val.canaddr()) }

这段代码的输出结果是:

false true

这表明,当我们直接传递a时,它是不可寻址的;而当我们传递&a时,它是可以被寻址的。

因此,在使用viper库时,我们需要传递指针的地址,而不是指针本身。这就是为什么在main模块中,我们需要使用&global.serversetting而不是global.serversetting。

通过这个例子,我们可以更好地理解go语言中指针的使用以及viper库的具体要求。希望这能帮助你在编写go程序时更好地处理指针和内存地址的问题。

以上就是在Go语言中使用viper库时,

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享