मैं () या नया () क्यों बनाऊंगा?


203

परिचय दस्तावेजों के बीच का अंतर समझा के लिए कई अनुच्छेदों को समर्पित करते हैं new()और make(), लेकिन व्यवहार में, आप स्थानीय दायरे के भीतर वस्तुओं को बनाने और उन्हें वापस कर सकते हैं।

आप आवंटितकर्ताओं की जोड़ी का उपयोग क्यों करेंगे?

जवाबों:


170

वे चीजें जो आप कर सकते हैं makeकि आप किसी अन्य तरीके से नहीं कर सकते हैं:

  • एक चैनल बनाएं
  • अंतरिक्ष उपदेश के साथ एक नक्शा बनाएँ
  • अंतरिक्ष प्रचार के साथ या लेन के साथ एक टुकड़ा बनाएँ! = टोपी

इसे सही ठहराना थोड़ा कठिन है new। मुख्य बात यह आसान बनाता है गैर-संयुक्त प्रकार के लिए संकेत पैदा कर रहा है। नीचे दिए गए दो कार्य बराबर हैं। एक थोड़ा और संक्षिप्त है:

func newInt1() *int { return new(int) }

func newInt2() *int {
    var i int
    return &i
}

41
यह सच है कि चैनल बनाने के लिए 'नए' का उपयोग नहीं किया जा सकता है। हालांकि, मेरी राय में, मुद्दा यह है: क्या होगा अगर 'नया' और 'मेक' एक ही अंतर्निहित फ़ंक्शन में शामिल हो जाएं? निश्चित रूप से, ऐसा प्रतिस्थापन संभव होगा। चूंकि यह संभव है, सवाल यह है: केवल 1 सामान्यीकृत फ़ंक्शन के बजाय 2 अंतर्निहित कार्यों के लिए उद्देश्य उद्देश्य क्या हैं। - आपका जवाब सही ढंग से कहा गया है कि 'नए' चैनल बनाने के लिए नहीं किया जा सकता / नक्शे / स्लाइस, लेकिन यह करने के लिए के रूप में औचित्य प्रदान नहीं करता है क्यों जाएँ 'नया' और 'मेक' है, बजाय 1 सामान्यीकृत alloc + init समारोह होने के।

5
उन्हें जोड़ा जा सकता है और यह एक बिंदु पर रोब पाइक द्वारा भी प्रस्तावित किया गया था: group.google.com/d/topic/golang-nuts/kWXYU95XN04/discussion । अंततः यह आपके उत्तर में दिए गए कारणों के समान नहीं था।
इवान शॉ

12
प्रभावी जाने से यह संकेत मिलता है कि नया एक शून्य मान देता है, जबकि नक्शा गैर-शून्य प्रकार का नक्शा, टुकड़ा या चैनल आवंटित करता है। Golang.org/doc/effective_go.html#allocation_new
kristianp

m := map[string]int{}इसके बारे में क्या m := make(map[string]int)? आकार के रूप में अच्छी तरह से प्रचार करने की कोई जरूरत नहीं है।
नोआम मानोस

165

स्मृति आवंटन और मूल्य आरंभीकरण के कई तरीके हैं:

&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अलग रहना उचित प्रतीत होता है ।


@TorstenBronger मुझे पढ़ना आसान लगता है और दिखाता है कि यह वह उदाहरण है जहां intबनाया गया है।
डैनियल टोबी

4
क्या आपको लिखने का मतलब था make(Point)और make(int)उन आखिरी 2 लाइनों में?
जिमी हच

27

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

1
में new([]int), यह सिर्फ [] int के लिए मेमोरी आवंटित करता है, लेकिन इनिशियलाइज़िंग नहीं करता है, इसलिए यह सिर्फ रिटर्न करता है nil; स्मृति के लिए सूचक नहीं क्योंकि यह अनुपयोगी है। make([]int)आबंटित और आरंभ करना इसलिए यह प्रयोग करने योग्य है, फिर इसका पता लौटाएं।
o0omycomputero0o

12
  • 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


  • उदाहरण के साथ चीजें अधिक स्पष्ट हो जाती हैं। upvoted :)
    सुमित झा

    8

    आपको make()चैनल और मानचित्र बनाने की आवश्यकता है (और स्लाइस, लेकिन उन्हें एरेज़ से भी बनाया जा सकता है)। उन्हें बनाने का कोई वैकल्पिक तरीका नहीं है, इसलिए आप make()अपने लेक्सिकन से नहीं निकाल सकते ।

    के रूप में new(), मैं किसी भी कारण से नहीं जानता कि आपको इसकी आवश्यकता क्यों है जब आप संरचना वाक्यविन्यास का उपयोग कर सकते हैं। इसका एक अनूठा अर्थ है, हालांकि, जो "शून्य मान के लिए आरंभिक सभी क्षेत्रों के साथ एक संरचना बनाता है और वापस लौटाता है", जो उपयोगी हो सकता है।


    1
    इसलिए नए से बचा जाना चाहिए और सिर्फ
    स्ट्रक्चर

    8

    इसके अलावा सब कुछ से में विस्तार से बताया प्रभावी जाओ , के बीच मुख्य अंतर new(T)और &T{}है कि बाद स्पष्ट रूप से एक ढेर आवंटन करता है। हालांकि यह ध्यान दिया जाना चाहिए कि यह कार्यान्वयन पर निर्भर है और इस प्रकार परिवर्तन के अधीन हो सकता है।

    दोनों की तुलना makeमें newथोड़ा अलग काम करने की तुलना में पूरी तरह से अलग कार्य करते हैं। लेकिन इससे जुड़े लेख में विस्तार से बताया गया है।


    10
    दावा है कि &T{}एक स्पष्ट रूप से ढेर आवंटन करता है AFAIK चश्मा में कुछ भी पर आधारित नहीं है। वास्तव में मेरा मानना ​​है कि भागने का विश्लेषण पहले से ही ऐसे टी को स्टैक पर रख रहा है जब भी संभव हो उसी तरह से new(T)
    zzzz

    6

    नया (T): यह T को टाइप * T का मान टाइप करने के लिए एक पॉइंटर लौटाता है , यह मेमोरी को आवंटित और शून्य करता है। नया (T) & T {} के बराबर है

    make (T): यह टाइप T का एक इनिशियलाइज्ड वैल्यू देता है , यह मेमोरी को आबंटित और आरंभ करता है। इसका उपयोग स्लाइस, मानचित्र और चैनलों के लिए किया जाता है।

    हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
    Licensed under cc by-sa 3.0 with attribution required.