淺談golang結構體偷懶初始化
執行一段程式,警告:
service/mysqlconfig.go:63::error: golang.guazi-corp.com/tools/ksql-runner/model.CreatingMysqlMongodbRecord composite literal uses unkeyed fields (vet)
其中,composite literal uses unkeyed fields這個警告找了很久原因,最終發現是結構體初始化的問題,自己埋雷。
例如,結構體定義如下,
type A struct { *B }
使用下邊無鍵欄位初始化,就會警告:
varA := A{b} // b is of type *B
在自己看來b的型別是B*,但編譯器卻不認賬。
正確初始化方法是:
a := A{B: b}
有人說是,這只是針對"go vet"中的一個錯誤的解決方法。
因為go vet預設情況下執行所有檢查,如果任何標誌顯式設定為true,則僅執行那些測試。
相反,如果任何標誌顯式設定為false,則僅禁用那些測試。
因此-printf = true執行printf檢查,-printf = false執行除printf檢查之外的所有檢查。
可以禁用這個檢查,也可以修改程式碼,但是規範程式碼更比較合適。
雖然這只是一個警告,有人覺得無關緊要,但是當你幾周或者幾個月後在結構體中添加了一個欄位,那麼你使用unkeyed初始化的所有東西都會被破壞。顯然,在一個專案中不希望遇到這種錯誤。
補充:golang中結構體的初始化方法(new方法)
準備工作:
定義結構體:Student
import ( "fmt" "reflect" ) type Student struct { StudentId string `json:"sid"` StudentName string `json:"sname"` StudentClass string `json:"class"` StudentTeacher string `json:"class"` }
測試程式碼如下:
func main() { s0 := Student{} fmt.Println(s0) fmt.Println(reflect.TypeOf(s0)) s1 := new(Student) fmt.Println(s1) fmt.Println(reflect.TypeOf(s1)) s2 := &Student{} fmt.Println(s2) fmt.Println(reflect.TypeOf(s2)) s3 := &Student{"","","100","200"} fmt.Println(s3) fmt.Println(reflect.TypeOf(s3)) s4:= &Student{StudentId: "100",StudentName: "200"} fmt.Println(s4) fmt.Println(reflect.TypeOf(s4)) }
輸出結果:
{ } main.Student &{ } *main.Student &{ } *main.Student &{ 100 200} *main.Student &{100 200 } *main.Student
注意:
除了s0以外,s1-s4變數全部為指向Rect結構的指標(指標變數),因為使用了new()函式和&操作符
而s0的方法 s0 := Student{} 表示的是一個Student型別,兩者是不一樣的
在Go語言中,未進行初始化的變數都會被初始化為該型別的零值,例如bool型別的零值為false,int型別的零值為0,string型別的零值為空字串. 在Go語言中沒有建構函式的概念,物件的建立通常交由一個全域性的建立函式來完成,以NewXXX來命令,表示"建構函式":
func NewStudent() { return &Student() //返回指標 }
用 new 分配記憶體 內建函式 new 本質上說跟其他語言中的同名函式功能一樣:new(T) 分配了零值填充的 T 型別的記憶體空間,並且返回其地址,一個 *T 型別的值。
務必記得 make 僅適用於 map,slice 和 channel,並且返回的不是指標。應當用 new獲得特定的指標。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援我們。如有錯誤或未考慮完全的地方,望不吝賜教。