Golang的匿名結(jié)構(gòu)是什么?
匿名結(jié)構(gòu)就像普通結(jié)構(gòu)一樣,但是它沒有名稱定義,因此不能在代碼的其他地方引用。Go中的結(jié)構(gòu)類似于C等其他語言中的結(jié)構(gòu)。它們是字段的類型化集合,用于將數(shù)據(jù)分組在一起,以使我們作為程序員更易于管理。要創(chuàng)建匿名結(jié)構(gòu),只需在聲明類型后立即實例化實例:
newCar := struct {
make string
model string
mileage int
}{
make: "Ford",
model: "Taurus",
mileage: 200000,
}
將其與創(chuàng)建結(jié)構(gòu)的“常規(guī)”方式進行對比:
// declare the 'car' struct type
type car struct {
make string
model string
mileage int
}
// create an instance of a car
newCar := car{
make: "Ford",
model: "taurus",
mileage: 200000,
}
什么時候應該使用匿名結(jié)構(gòu)?
我經(jīng)常使用匿名結(jié)構(gòu)在HTTP處理程序中封裝和解封JSON數(shù)據(jù)。如果一個結(jié)構(gòu)只打算被使用一次,那么以這樣一種方式聲明它是有意義的,即使得開發(fā)人員不會試圖再次使用它。看下面的代碼。我們能夠?qū)TTP請求直接解析到newCar結(jié)構(gòu)中,而無需給結(jié)構(gòu)命名。仍然可以通過點運算符訪問所有字段,但是我們不必擔心項目的另一部分嘗試使用非預期類型。
func createCarHandler(w http.ResponseWriter, req *http.Request) {
defer req.Body.Close()
decoder := json.NewDecoder(req.Body)
newCar := struct {
Make string `json:"make"`
Model string `json:"model"`
Mileage int `json:"mileage"`
}{}
err := decoder.Decode(&newCar)
if err != nil {
log.Println(err)
return
}
makeCar(newCar.Make, newCar.Model, newCar.Mileage)
return
}
map[string]interface{}如果可以避免,請不要用于JSON數(shù)據(jù)。
我經(jīng)常看到使用map[string]interface{},而不是聲明用于JSON解組的快速匿名結(jié)構(gòu)。在大多數(shù)情況下,這是很糟糕的,原因如下:
- 1、沒有類型檢查。如果客戶端發(fā)送稱為“Model”的密鑰作為bool,但應該是string,則解析到map中將無法捕獲錯誤
- 2、map是模糊的。解析數(shù)據(jù)后,我們被迫使用運行時檢查來確保我們關(guān)心的數(shù)據(jù)存在。如果這些檢查不徹底,則可能導致拋出nil指針取消引用panic。
- 3、map[string]interface{}很冗長。深入研究map并不像使用點運算符訪問命名字段那樣簡單newCar.model。相反,它類似于:
func createCarHandler(w http.ResponseWriter, req *http.Request) {
myMap := map[string]interface{}{}
decoder := json.NewDecoder(req.Body)
err := decoder.Decode(&myMap)
if err != nil {
log.Println(err)
return
}
model, ok := myMap["model"]
if !ok {
fmt.Println("field doesn't exist")
return
}
modelString, ok := model.(string)
if !ok {
fmt.Println("model is not a string")
}
// do something with model field
}
如果使用正確,匿名結(jié)構(gòu)可以清理您的API處理程序。他們提供的強類型輸入同時仍是“一次性”解決方案,是一個強大的工具。