go指針語(yǔ)法及viper庫(kù)使用中的尋址問題
在使用go語(yǔ)言進(jìn)行編程時(shí),理解指針的語(yǔ)法和使用方法至關(guān)重要,尤其是在與第三方庫(kù)如viper結(jié)合使用時(shí),可能會(huì)遇到一些需要深入理解的問題。今天我們要探討的問題是關(guān)于在viper庫(kù)的使用中,如何正確地傳遞參數(shù),以及為什么傳遞一個(gè)指針的指針是必要的。
在我們的項(xiàng)目中有幾個(gè)模塊: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模塊:
立即學(xué)習(xí)“go語(yǔ)言免費(fèi)學(xué)習(xí)筆記(深入)”;
var serversetting *setting.serversettings
main模塊:
setting, err := setting.newsetting() setting.readsection("server", &global.serversetting)
現(xiàn)在,如果在main模塊中將第二行修改為setting.readsection(“server”, global.serversetting),會(huì)報(bào)錯(cuò)result must be addressable (a pointer)。這是為什么呢?
問題在于,global.serversetting已經(jīng)是一個(gè)指針,為什么在調(diào)用readsection方法時(shí),還需要傳遞它的地址呢?
在viper庫(kù)的源碼中有這樣的說(shuō)明:
// 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)") } }
從這段代碼可以看出,傳遞的參數(shù)不僅需要是一個(gè)指針,還需要是可以尋址的(can be addressable)。當(dāng)你傳遞一個(gè)結(jié)構(gòu)體的指針時(shí),它本身并不能被尋址,因此會(huì)導(dǎo)致錯(cuò)誤。
為了驗(yàn)證這一點(diǎn),我們可以看一下下面的例子:
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()) }
運(yùn)行這段代碼會(huì)得到如下輸出:
false true
這表明傳遞a本身(即一個(gè)指針)時(shí),其元素?zé)o法被尋址,而傳遞&a(即指針的指針)時(shí),其元素是可以被尋址的。
因此,在使用readsection方法時(shí),我們需要傳遞&global.serversetting,因?yàn)檫@樣傳遞的是一個(gè)指針的地址,它是可以被尋址的,從而滿足viper庫(kù)的要求。
以上就是在使用go語(yǔ)言和viper庫(kù)時(shí),