Yanıtlar:
Eğer yapabileceğiniz şeyler make
size başka bir şekilde yapamaz:
Haklı çıkarmak biraz daha zor new
. Daha kolay hale getirdiği ana şey, kompozit olmayan türlere işaretçiler oluşturmaktır. Aşağıdaki iki işlev eşdeğerdir. Kişi biraz daha özlü:
func newInt1() *int { return new(int) }
func newInt2() *int {
var i int
return &i
}
m := map[string]int{}
yerine ne olacak m := make(map[string]int)
? boyutu da önceden konumlandırmaya gerek yok.
Go'nun birden fazla bellek ayırma ve değer başlatma yöntemi vardır:
&T{...}
, &someLocalVar
, new
,make
Tahsis, bileşik değişmez değerler oluştururken de olabilir.
new
tamsayı gibi değerleri ayırmak için kullanılabilir &int
, yasadışıdır:
new(Point)
&Point{} // OK
&Point{2, 3} // Combines allocation and initialization
new(int)
&int // Illegal
// Works, but it is less convenient to write than new(int)
var i int
&i
Arasındaki fark new
ve make
aşağıdaki örneğe bakarak görülebilir:
p := new(chan int) // p has type: *chan int
c := make(chan int) // c has type: chan int
Farz edelim ki Go yoktur new
ve make
yerleşik fonksiyona sahiptir NEW
. Sonra örnek kod şöyle görünecektir:
p := NEW(*chan int) // * is mandatory
c := NEW(chan int)
*
Zorunlu olacaktır böylece:
new(int) --> NEW(*int)
new(Point) --> NEW(*Point)
new(chan int) --> NEW(*chan int)
make([]int, 10) --> NEW([]int, 10)
new(Point) // Illegal
new(int) // Illegal
Evet, birleştirme new
ve make
tek bir yerleşik fonksiyonda mümkündür. Ancak, tek bir yerleşik işlevin, yeni Go programcıları arasında iki yerleşik işleve sahip olmaktan daha fazla karışıklığa yol açması muhtemeldir.
Yukarıdaki noktaların tümü göz önüne alındığında, ayrı kalmak new
ve make
kalmak daha uygun görünmektedir .
int
bunun oluşturulduğu örnek olduğunu gösteriyor .
make(Point)
ve make(int)
bu son 2 hatlarında?
make
işlevi yalnızca dilim, harita veya chan türündeki bir nesneyi ayırır ve başlatır. Gibi new
, ilk argüman türüdür. Ancak, ikinci bir argüman da alabilir. Yeni öğeden farklı olarak, make'in dönüş türü, bir işaretçi değil, bağımsız değişkeninin türüyle aynıdır. Ve tahsis edilen değer başlatılır (yeni gibi sıfır değerine ayarlanmamıştır). Bunun nedeni, dilim, harita ve chan'ın veri yapıları olmasıdır. Başlatılmaları gerekir, aksi takdirde kullanılamazlar. New () ve make () 'in farklı olmasının nedeni budur.
Aşağıdaki Effective Go örnekleri çok açıktır:
p *[]int = new([]int) // *p = nil, which makes p useless
v []int = make([]int, 100) // creates v structure that has pointer to an array, length field, and capacity field. So, v is immediately usable
new([]int)
, sadece [] int için bellek ayırır, ancak başlatılmaz nil
; işaretçi hafızaya değil çünkü kullanılamaz. make([]int)
kullanılabilir hale getirmek için ayırır ve başlatır, ardından adresini döndürür.
new(T)
- Belleği ayırır ve T tipi için sıfır değerine ayarlar .
..o 0
için int , ""
için dize ve nil
başvurulan türleri ( dilim , harita , Chan )
Referans verilen türlerin yalnızca temel veri yapıları , oluşturulan olmaz tarafından new(T)
durumunda: Örnek dilim , altta yatan dizisi oluşturulmaz dolayısıyla new([]int)
hiçbir şey bir gösterici ile döner
make(T)
- Referans verilen veri türleri ( dilim , harita , chan ) için bellek ayırır ve bunların temelini oluşturan veri yapılarını başlatır
Örnek: dilim durumunda , alttaki dizi belirtilen uzunluk ve kapasitede oluşturulacaktır.
C'den farklı olarak, bir dizinin Go!
Söyleniyor ki:
make(T)
kompozit-literal sözdizimi gibi davranır
new(T)
gibi davranır var
(değişken başlatılmadığında)
func main() {
fmt.Println("-- MAKE --")
a := make([]int, 0)
aPtr := &a
fmt.Println("pointer == nil :", *aPtr == nil)
fmt.Printf("pointer value: %p\n\n", *aPtr)
fmt.Println("-- COMPOSITE LITERAL --")
b := []int{}
bPtr := &b
fmt.Println("pointer == nil :", *bPtr == nil)
fmt.Printf("pointer value: %p\n\n", *bPtr)
fmt.Println("-- NEW --")
cPtr := new([]int)
fmt.Println("pointer == nil :", *cPtr == nil)
fmt.Printf("pointer value: %p\n\n", *cPtr)
fmt.Println("-- VAR (not initialized) --")
var d []int
dPtr := &d
fmt.Println("pointer == nil :", *dPtr == nil)
fmt.Printf("pointer value: %p\n", *dPtr)
}
Programı çalıştır
-- MAKE --
pointer == nil : false
pointer value: 0x118eff0 # address to underlying array
-- COMPOSITE LITERAL --
pointer == nil : false
pointer value: 0x118eff0 # address to underlying array
-- NEW --
pointer == nil : true
pointer value: 0x0
-- VAR (not initialized) --
pointer == nil : true
pointer value: 0x0
Daha fazla okuma:
https://golang.org/doc/effective_go.html#allocation_new
https://golang.org/doc/effective_go.html#allocation_make
make()
Kanallar ve haritalar oluşturmanız gerekir (ve dilimler, ancak bunlar dizilerden de oluşturulabilir). Bunları yapmanın alternatif bir yolu yok, bu yüzden kaldıramazsınızmake()
sözlüğünüzden .
Gelince new()
, struct sözdizimini kullanabildiğinizde neden ihtiyacınız olduğunu hiçbir neden bilmiyorum . Bununla birlikte, "yararlı olabilecek tüm alanları sıfır değerine sıfırlanmış bir yapı oluşturma ve döndürme" olan benzersiz bir anlamsal anlamı vardır.
Dışında her şeyi açıklandığı Etkili Go , ana fark arasındaki new(T)
ve&T{}
, ikincisinin açıkça bir yığın tahsisi gerçekleştirmesidir. Bununla birlikte, bunun uygulamaya bağlı olduğu ve bu nedenle değişikliğe tabi olabileceği unutulmamalıdır.
Karşılaştırma make
için new
birbirinden tamamen farklı işlevleri yerine kadar az mantıklı. Ancak bu, bağlantılı makalede ayrıntılı olarak açıklanmaktadır.
&T{}
Açıkça bir yığın tahsisi gerçekleştiren iddia , spesifikasyonlardaki herhangi bir şeye dayanmayan AFAIK'tır. Aslında kaçış analizinin mümkün olduğunca böylesi bir * T yığını üzerinde tuttuğuna inanıyorum new(T)
.