問題探討:在go語言中使用viper庫時(shí)的指針傳參問題
在編寫go程序時(shí),經(jīng)常會(huì)遇到關(guān)于指針和內(nèi)存地址的問題。尤其是在使用第三方庫如viper時(shí),指針的使用更加復(fù)雜。本文將通過一個(gè)具體的例子,詳細(xì)解釋在go語言中使用viper庫時(shí)的指針傳參問題。
首先,我們來看一下代碼示例:
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模塊:
立即學(xué)習(xí)“go語言免費(fèi)學(xué)習(xí)筆記(深入)”;
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)
在上述代碼中,如果我們?cè)趍ain模塊中將第二行修改為setting.readsection(“server”, global.serversetting),程序會(huì)報(bào)錯(cuò)result must be addressable (a pointer)。為什么會(huì)出現(xiàn)這個(gè)問題呢?
首先需要明確的是,雖然global.serversetting是一個(gè)指針,但這并不意味著它可以被直接傳遞給readsection函數(shù)。我們需要傳遞的是指針的地址,而不是指針本身。
要理解這一點(diǎn),我們需要深入viper庫的源碼。在viper庫的newdecoder函數(shù)中,有這樣一段代碼:
// 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)") } }
這段代碼說明了問題的關(guān)鍵:傳遞的參數(shù)不僅需要是一個(gè)指針,還必須是可以被尋址的(addressable)。當(dāng)我們傳遞一個(gè)結(jié)構(gòu)體的指針時(shí),它并不能被尋址,因此會(huì)報(bào)錯(cuò)。
為了進(jìn)一步理解這個(gè)問題,我們可以看一個(gè)簡單的例子:
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()) }
這段代碼的輸出結(jié)果是:
false true
這表明,當(dāng)我們直接傳遞a時(shí),它是不可尋址的;而當(dāng)我們傳遞&a時(shí),它是可以被尋址的。
因此,在使用viper庫時(shí),我們需要傳遞指針的地址,而不是指針本身。這就是為什么在main模塊中,我們需要使用&global.serversetting而不是global.serversetting。
通過這個(gè)例子,我們可以更好地理解go語言中指針的使用以及viper庫的具體要求。希望這能幫助你在編寫go程序時(shí)更好地處理指針和內(nèi)存地址的問題。