3 回答

TA貢獻1798條經驗 獲得超7個贊
當你聲明一個變量時, whereT是某種類型:
var name T
Go 給你一塊未初始化的“歸零”內存。
對于原語,這意味著var name int它將是 0,并且var name string將是“”。在C 中,它可能被歸零,或者可能是出乎意料的。Go 保證未初始化的變量是該類型的零等價物。
在內部,切片、映射和通道被視為指針。指針零值為零,意味著它指向零內存。如果沒有初始化它,如果您嘗試對其進行操作,您可能會遇到恐慌。
該make函數是專門為切片、貼圖或通道設計的。make 函數的參數是:
make(T type, length int[, capacity int]) // For slices.
make(T[, capacity int]) // For a map.
make(T[, bufferSize int]) // For a channel. How many items can you take without blocking?
切片length是它以多少個項目開頭。容量是在需要調整大小之前分配的內存(內部,新大小 * 2,然后復制)。有關更多信息,請參閱Effective Go:使用 make 分配。
結構:new(T)等價于&T{},而不是T{}。*new(T)相當于*&T{}。
切片:make([]T,0)相當于[]T{}.
地圖:make(map[T]T)相當于map[T]T{}.
至于首選哪種方法,我問自己以下問題:
我現在知道函數內的值嗎?
如果答案是“是”,那么我會選擇上述之一T{...}。如果答案是“否”,那么我使用 make 或 new。
例如,我會避免這樣的事情:
type Name struct {
FirstName string
LastName string
}
func main() {
name := &Name{FirstName:"John"}
// other code...
name.LastName = "Doe"
}
相反,我會做這樣的事情:
func main() {
name := new(Name)
name.FirstName = "John"
// other code...
name.LastName = "Doe"
}
為什么?因為通過使用new(Name)我明確表示我打算稍后填充這些值。如果我使用&Name{...}它就不清楚我打算稍后在同一函數中添加/更改值而不閱讀其余代碼。
當您不需要指針時,結構是例外。我將使用T{},但如果我打算添加/更改值,我不會在其中添加任何內容。當然*new(T)也有效,但這就像使用*&T{}. T{}在這種情況下更干凈,盡管我傾向于使用帶有結構的指針來避免在傳遞時進行復制。
另一件要記住的事情是, a[]*struct比 更小,調整大小更便宜[]struct,假設結構比指針大得多,指針通常為 4 - 8 個字節(64 位上為 8 個字節?)。

TA貢獻1864條經驗 獲得超2個贊
您可以查看 Go 標準庫源,在那里您可以找到許多慣用的 Go 代碼。
您是對的:var xs []int
與其他兩個變體不同,因為它不“初始化”xs,xs 為零。而另外兩個確實構造了一個切片。xs := []int{}
如果您需要一個零上限的空切片,則很常見,同時make
為您提供更多選擇:長度和容量。另一方面,通常從一個 nil 切片開始并通過附加來填充var s []int; for ... { s = append(s, num) }
。
new
完全無法避免,因為它是創建指針的唯一方法,例如指向 uint32 或其他內置類型。但你是對的,寫作a := new(A)
是非常罕見的,主要是a := &A{}
因為這可以變成a := &A{n: 17, whatever: "foo"}
. 使用 ofnew
并不是真的不鼓勵,但考慮到結構文字的能力,對我來說它只是 Java 的遺留物。
- 3 回答
- 0 關注
- 284 瀏覽
添加回答
舉報