Jawaban:
Hal-hal yang dapat Anda lakukan dengan makeyang tidak dapat Anda lakukan dengan cara lain:
Agak sulit untuk dibenarkan new. Hal utama yang membuatnya lebih mudah adalah membuat pointer ke tipe non-komposit. Dua fungsi di bawah ini setara. Satu hanya sedikit lebih ringkas:
func newInt1() *int { return new(int) }
func newInt2() *int {
var i int
return &i
}
m := map[string]int{}sebaliknya m := make(map[string]int)? tidak perlu mengalokasikan ukuran juga.
Go memiliki banyak cara alokasi memori dan inisialisasi nilai:
&T{...}, &someLocalVar, new,make
Alokasi juga dapat terjadi saat membuat literal komposit.
newdapat digunakan untuk mengalokasikan nilai-nilai seperti bilangan bulat, &intilegal:
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
Perbedaan antara newdan makedapat dilihat dengan melihat contoh berikut:
p := new(chan int) // p has type: *chan int
c := make(chan int) // c has type: chan int
Misalkan Go tidak memiliki newdan make, tetapi memiliki fungsi bawaan NEW. Maka kode contoh akan terlihat seperti ini:
p := NEW(*chan int) // * is mandatory
c := NEW(chan int)
Itu * wajib , jadi:
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
Ya, menggabungkan newdan makemenjadi satu fungsi bawaan dimungkinkan. Namun, ada kemungkinan bahwa fungsi built-in tunggal akan menyebabkan lebih banyak kebingungan di antara programmer Go daripada memiliki dua fungsi built-in.
Mempertimbangkan semua poin di atas, tampaknya lebih tepat untuk newdan maketetap terpisah.
intdibuat.
make(Point)dan make(int)dalam 2 baris terakhir?
makefungsi mengalokasikan dan menginisialisasi objek dengan tipe slice, map, atau chan only. Seperti new, argumen pertama adalah tipe. Tapi, bisa juga argumen kedua, ukuran. Tidak seperti yang baru, tipe return make sama dengan tipe argumennya, bukan pointer. Dan nilai yang dialokasikan diinisialisasi (tidak diatur ke nilai nol seperti yang baru). Alasannya adalah bahwa slice, map dan chan adalah struktur data. Mereka perlu diinisialisasi, kalau tidak mereka tidak akan dapat digunakan. Inilah alasan baru () dan make () harus berbeda.
Contoh-contoh berikut dari Effective Go membuatnya sangat jelas:
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), itu hanya mengalokasikan memori untuk [] int, tetapi tidak menginisialisasi sehingga hanya mengembalikan nil; bukan penunjuk ke memori karena tidak dapat digunakan. make([]int)mengalokasikan dan menginisialisasi sehingga dapat digunakan, lalu kembalikan alamatnya.
new(T)- Mengalokasikan memori, dan menetapkannya ke nilai nol untuk jenis T ..
..that adalah 0untuk int , ""untuk tali dan niluntuk jenis direferensikan ( slice , peta , chan )
Perhatikan bahwa tipe yang direferensikan hanyalah pointer ke beberapa struktur data yang mendasarinya , yang tidak akan dibuat oleh new(T)
Contoh: dalam kasus slice , array yang mendasarinya tidak akan dibuat, sehingga new([]int)
mengembalikan pointer ke nol.
make(T)- memori Alokasikan untuk jenis direferensikan data ( slice , peta , chan ), ditambah menginisialisasi mereka struktur data yang mendasari
Contoh: dalam kasus slice , array yang mendasarinya akan dibuat dengan panjang dan kapasitas yang ditentukan.
Ingatlah, tidak seperti C, array adalah tipe primitif di Go!
Yang telah dibilang:
make(T) berperilaku seperti sintaks komposit-literal
new(T)berperilaku seperti var(ketika variabel tidak diinisialisasi)
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)
}
Jalankan programnya
-- 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
Bacaan lebih lanjut:
https://golang.org/doc/effective_go.html#allocation_new
https://golang.org/doc/effective_go.html#allocation_make
Anda perlu make()membuat saluran dan peta (dan irisan, tetapi itu juga dapat dibuat dari array). Tidak ada cara alternatif untuk membuatnya, jadi Anda tidak bisa menghapusnyamake() dari leksikon Anda.
Adapun new(), saya tidak tahu alasan apa pun begitu saja mengapa Anda membutuhkannya ketika Anda dapat menggunakan sintaks struct. Itu memang memiliki makna semantik yang unik, yaitu "membuat dan mengembalikan struct dengan semua bidang diinisialisasi ke nilai nol", yang dapat berguna.
Terlepas dari semua yang dijelaskan dalam Efektif Go , Perbedaan utama antara new(T)dan &T{}adalah bahwa yang terakhir secara eksplisit melakukan alokasi tumpukan. Namun perlu dicatat bahwa ini tergantung pada implementasi dan karenanya dapat berubah.
Dibandingkan makedengan newsedikit masuk akal karena keduanya melakukan fungsi yang sama sekali berbeda. Tetapi ini dijelaskan secara rinci dalam artikel yang ditautkan.
&T{}secara eksplisit melakukan alokasi tumpukan adalah AFAIK tidak didasarkan pada apa pun dalam spesifikasi. Sebenarnya saya percaya analisis melarikan diri sudah menyimpan * T pada stack bila memungkinkan dengan cara yang sama persis dengan new(T).