जवाबों:
वे चीजें जो आप कर सकते हैं make
कि आप किसी अन्य तरीके से नहीं कर सकते हैं:
इसे सही ठहराना थोड़ा कठिन है new
। मुख्य बात यह आसान बनाता है गैर-संयुक्त प्रकार के लिए संकेत पैदा कर रहा है। नीचे दिए गए दो कार्य बराबर हैं। एक थोड़ा और संक्षिप्त है:
func newInt1() *int { return new(int) }
func newInt2() *int {
var i int
return &i
}
m := map[string]int{}
इसके बारे में क्या m := make(map[string]int)
? आकार के रूप में अच्छी तरह से प्रचार करने की कोई जरूरत नहीं है।
स्मृति आवंटन और मूल्य आरंभीकरण के कई तरीके हैं:
&T{...}
, &someLocalVar
, new
,make
समग्र शाब्दिक निर्माण करते समय आवंटन भी हो सकता है।
new
पूर्णांक जैसे मानों को आवंटित करने के लिए इस्तेमाल किया जा सकता है, &int
अवैध है:
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
के बीच का अंतर new
और make
निम्न उदाहरण को देखकर देखा जा सकता है:
p := new(chan int) // p has type: *chan int
c := make(chan int) // c has type: chan int
मान लीजिए कि गो के पास new
और नहीं है make
, लेकिन इसमें अंतर्निहित कार्य है NEW
। फिर उदाहरण कोड इस तरह दिखेगा:
p := NEW(*chan int) // * is mandatory
c := NEW(chan int)
यह *
अनिवार्य होगा , इसलिए:
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
हां, विलय new
और make
एक ही अंतर्निहित फ़ंक्शन में संभव है। हालांकि, यह संभव है कि एक एकल निर्मित फ़ंक्शन दो निर्मित कार्यों की तुलना में नए गो प्रोग्रामर के बीच अधिक भ्रम पैदा करेगा।
उपरोक्त सभी बिंदुओं पर विचार करते हुए, यह अलग होना new
और make
अलग रहना उचित प्रतीत होता है ।
int
बनाया गया है।
make(Point)
और make(int)
उन आखिरी 2 लाइनों में?
make
फ़ंक्शन केवल स्लाइस, मैप या चान के ऑब्जेक्ट को आवंटित करता है और आरंभ करता है। जैसे new
, पहला तर्क एक प्रकार है। लेकिन, यह एक दूसरा तर्क भी ले सकता है, आकार। नए के विपरीत, मेक का रिटर्न प्रकार उसके तर्क के प्रकार के समान है, न कि इसके लिए सूचक। और आबंटित मूल्य आरंभीकृत है (नए की तरह शून्य मान पर सेट नहीं)। कारण यह है कि टुकड़ा, नक्शा और चान डेटा संरचनाएं हैं। उन्हें आरंभ करने की आवश्यकता है, अन्यथा वे उपयोग करने योग्य नहीं होंगे। यही कारण है कि नया () और मेक () अलग होना चाहिए।
प्रभावी गो से निम्नलिखित उदाहरण इसे बहुत स्पष्ट करते हैं:
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)
, यह सिर्फ [] int के लिए मेमोरी आवंटित करता है, लेकिन इनिशियलाइज़िंग नहीं करता है, इसलिए यह सिर्फ रिटर्न करता है nil
; स्मृति के लिए सूचक नहीं क्योंकि यह अनुपयोगी है। make([]int)
आबंटित और आरंभ करना इसलिए यह प्रयोग करने योग्य है, फिर इसका पता लौटाएं।
new(T)
- आवंटित स्मृति, और यह करने के लिए सेट शून्य मान प्रकार के लिए टी ..
..that है 0
के लिए पूर्णांक , ""
के लिए स्ट्रिंग और nil
संदर्भित प्रकार (के लिए टुकड़ा , नक्शा , चान )
ध्यान दें कि संदर्भित प्रकार कुछ अंतर्निहित डेटा संरचनाओं के लिए संकेत हैं , जो
उदाहरण के द्वारा नहीं बनाया जाएगाnew(T)
: स्लाइस के मामले में , अंतर्निहित सरणी नहीं बनाई जाएगी, इस प्रकार new([]int)
एक सूचक को कुछ भी नहीं लौटाता है
make(T)
- संदर्भित डेटा प्रकारों ( स्लाइस , मैप , चान ) के लिए मेमोरी आवंटित करता है , साथ ही उनके अंतर्निहित डेटा संरचनाओं को इनिशियलाइज़ करता है
उदाहरण: स्लाइस के मामले में , अंतर्निहित सरणी को निर्दिष्ट लंबाई और क्षमता के साथ बनाया जाएगा
ध्यान रखें कि, सी के विपरीत, एक सरणी गो में एक आदिम प्रकार है!
ऐसा कहे जाने के बाद:
make(T)
समग्र-शाब्दिक वाक्य-विन्यास की तरह व्यवहार करता है
new(T)
जैसा व्यवहार करता है var
(जब चर आरंभीकृत नहीं होता है)
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)
}
प्रोग्राम चलाएं
-- 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
आगे पढ़े:
https://golang.org/doc/effective_go.html#allocation_new
https://golang.org/doc/effective_go.html#allocation_make
आपको make()
चैनल और मानचित्र बनाने की आवश्यकता है (और स्लाइस, लेकिन उन्हें एरेज़ से भी बनाया जा सकता है)। उन्हें बनाने का कोई वैकल्पिक तरीका नहीं है, इसलिए आप make()
अपने लेक्सिकन से नहीं निकाल सकते ।
के रूप में new()
, मैं किसी भी कारण से नहीं जानता कि आपको इसकी आवश्यकता क्यों है जब आप संरचना वाक्यविन्यास का उपयोग कर सकते हैं। इसका एक अनूठा अर्थ है, हालांकि, जो "शून्य मान के लिए आरंभिक सभी क्षेत्रों के साथ एक संरचना बनाता है और वापस लौटाता है", जो उपयोगी हो सकता है।
इसके अलावा सब कुछ से में विस्तार से बताया प्रभावी जाओ , के बीच मुख्य अंतर new(T)
और &T{}
है कि बाद स्पष्ट रूप से एक ढेर आवंटन करता है। हालांकि यह ध्यान दिया जाना चाहिए कि यह कार्यान्वयन पर निर्भर है और इस प्रकार परिवर्तन के अधीन हो सकता है।
दोनों की तुलना make
में new
थोड़ा अलग काम करने की तुलना में पूरी तरह से अलग कार्य करते हैं। लेकिन इससे जुड़े लेख में विस्तार से बताया गया है।
&T{}
एक स्पष्ट रूप से ढेर आवंटन करता है AFAIK चश्मा में कुछ भी पर आधारित नहीं है। वास्तव में मेरा मानना है कि भागने का विश्लेषण पहले से ही ऐसे टी को स्टैक पर रख रहा है जब भी संभव हो उसी तरह से new(T)
।
नया (T): यह T को टाइप * T का मान टाइप करने के लिए एक पॉइंटर लौटाता है , यह मेमोरी को आवंटित और शून्य करता है। नया (T) & T {} के बराबर है ।
make (T): यह टाइप T का एक इनिशियलाइज्ड वैल्यू देता है , यह मेमोरी को आबंटित और आरंभ करता है। इसका उपयोग स्लाइस, मानचित्र और चैनलों के लिए किया जाता है।