go指針語法及viper庫使用中的尋址問題
在使用go語言進行編程時,理解指針的語法和使用方法至關重要,尤其是在與第三方庫如viper結合使用時,可能會遇到一些需要深入理解的問題。今天我們要探討的問題是關于在viper庫的使用中,如何正確地傳遞參數,以及為什么傳遞一個指針的指針是必要的。
在我們的項目中有幾個模塊:setting、section、global和main。具體代碼如下:
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模塊:
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模塊:
立即學習“go語言免費學習筆記(深入)”;
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庫的源碼中有這樣的說明:
// 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)") } }
從這段代碼可以看出,傳遞的參數不僅需要是一個指針,還需要是可以尋址的(can be 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(即指針的指針)時,其元素是可以被尋址的。
因此,在使用readsection方法時,我們需要傳遞&global.serversetting,因為這樣傳遞的是一個指針的地址,它是可以被尋址的,從而滿足viper庫的要求。
以上就是在使用go語言和viper庫時,