आप गो में एक टुकड़ा कैसे साफ़ करते हैं?


125

गो में एक स्लाइस को साफ करने का उपयुक्त तरीका क्या है?

यहाँ मैंने जाने के मंचों में क्या पाया है :

// test.go
package main

import (
    "fmt"
)

func main() {
    letters := []string{"a", "b", "c", "d"}
    fmt.Println(cap(letters))
    fmt.Println(len(letters))
    // clear the slice
    letters = letters[:0]
    fmt.Println(cap(letters))
    fmt.Println(len(letters))
}

क्या ये सही है?

स्पष्ट करने के लिए, बफर को साफ किया जाता है ताकि इसे पुन: उपयोग किया जा सके।

एक उदाहरण बाइट्स पैकेज में बफ़ररुनेट फ़ंक्शन है।

ध्यान दें कि रीसेट केवल Truncate (0) को कॉल करता है। तो ऐसा प्रतीत होता है कि इस मामले में रेखा 70 का मूल्यांकन करेगी: b.buf = b.buf [0: 0]

http://golang.org/src/pkg/bytes/buffer.go

// Truncate discards all but the first n unread bytes from the buffer.
60  // It panics if n is negative or greater than the length of the buffer.
61  func (b *Buffer) Truncate(n int) {
62      b.lastRead = opInvalid
63      switch {
64      case n < 0 || n > b.Len():
65          panic("bytes.Buffer: truncation out of range")
66      case n == 0:
67          // Reuse buffer space.
68          b.off = 0
69      }
70      b.buf = b.buf[0 : b.off+n]
71  }
72  
73  // Reset resets the buffer so it has no content.
74  // b.Reset() is the same as b.Truncate(0).
75  func (b *Buffer) Reset() { b.Truncate(0) }

1
इस पर एक त्वरित परीक्षण: play.golang.org/p/6Z-qDQtpbg यह सुझाव देता है कि यह काम करेगा (क्षमता नहीं बदलेगा लेकिन यह लंबाई को कम कर देगा)
जेसन स्पर्सके

जवाबों:


120

यह सब इस बात पर निर्भर करता है कि आपकी 'स्पष्ट' की परिभाषा क्या है। मान्य लोगों में से एक निश्चित रूप से है:

slice = slice[:0]

लेकिन एक पकड़ है। यदि स्लाइस तत्व प्रकार T के हैं:

var slice []T

फिर len(slice)उपरोक्त "ट्रिक" द्वारा शून्य होने के लिए, किसी भी तत्व का निर्माण नहीं करता है

slice[:cap(slice)]

कचरा संग्रहण के लिए पात्र। यह कुछ परिदृश्यों में इष्टतम दृष्टिकोण हो सकता है। लेकिन यह "मेमोरी लीक" का भी कारण हो सकता है - मेमोरी का उपयोग नहीं किया जाता है, लेकिन संभावित रूप से पहुंच योग्य ('स्लाइस' के फिर से स्लाइसिंग के बाद) और इस तरह "संग्रहणीय" कचरा नहीं।


1
दिलचस्प। क्या किसी अन्य तरीके से स्लाइस के अंतर्निहित सरणी से सभी तत्वों को हटाने के लिए अंतर्निहित क्षमता को अपरिवर्तित छोड़ दिया जाता है?
क्रिस वेबर

3
@ क्रिस वेबर: बस अंतर्निहित सरणी पर पुनरावृति करें और सभी तत्वों को एक नए मूल्य पर सेट करें
14

2
@jnml, मैं स्लाइस (और अंतर्निहित एरे स्टोरेज) का पुन: उपयोग करना चाहता हूं, इसलिए मैं लगातार एक नया स्लाइस (सरणी के साथ) आवंटित नहीं कर रहा हूं। मैंने अपने प्रश्न को स्पष्ट करने और मानक पुस्तकालय से कुछ उदाहरण कोड दिखाने के लिए संपादित किया है।
क्रिस वेबर

1
मैं नया हूं। क्या आप कृपया इस बारे में अधिक बता सकते हैं कि यह एक इष्टतम दृष्टिकोण क्यों हो सकता है? अग्रिम में धन्यवाद।
सटोरू

क्या आप सुनिश्चित हैं कि स्लाइस आकार रीसेट मेमोरी लीक का कारण बनता है? मैं इसे पुन: पेश करने में सक्षम नहीं हूं
टॉमसो बारबुगली

197

स्लाइस nilको साफ करने का सबसे अच्छा तरीका है स्लाइस को सेट करना । nilजाने में स्लाइस पूरी तरह से अच्छी तरह से व्यवहार किया जाता है और स्लाइस को स्थापित करने के लिएnil कचरे को कलेक्टर को अंतर्निहित मेमोरी जारी करेगा।

खेल का मैदान देखें

package main

import (
    "fmt"
)

func dump(letters []string) {
    fmt.Println("letters = ", letters)
    fmt.Println(cap(letters))
    fmt.Println(len(letters))
    for i := range letters {
        fmt.Println(i, letters[i])
    }
}

func main() {
    letters := []string{"a", "b", "c", "d"}
    dump(letters)
    // clear the slice
    letters = nil
    dump(letters)
    // add stuff back to it
    letters = append(letters, "e")
    dump(letters)
}

प्रिंटों

letters =  [a b c d]
4
4
0 a
1 b
2 c
3 d
letters =  []
0
0
letters =  [e]
1
1
0 e

ध्यान दें कि स्लाइस को आसानी से उतारा जा सकता है ताकि दो स्लाइस एक ही अंतर्निहित स्मृति को इंगित करें। सेटिंग nilउस एलियासिंग को हटा देगी।

यह विधि यद्यपि शून्य करने की क्षमता को बदलती है।


प्रतिक्रिया के लिए धन्यवाद। कृपया मेरा अपडेट देखें यह आप करेंगे। मैं पुन: उपयोग के लिए टुकड़ा साफ कर रहा हूँ। इसलिए मैं जरूरी नहीं चाहता कि जीसी के लिए जारी की गई अंतर्निहित स्मृति, क्योंकि मुझे इसे फिर से आवंटित करना होगा।
क्रिस वेबर

यह वही है जो मैंने खोजा था!)
तैमूर फैज़्रखमानोव

5
शीर्षक के आधार पर "आप गो में एक टुकड़ा कैसे साफ़ करें?" यह दूर और सुरक्षित उत्तर है और इसे स्वीकार किया जाना चाहिए। एक सही उत्तर मूल रूप से स्वीकृत उत्तर का संयोजन होगा और यह एक ऐसा व्यक्ति है जो स्वयं के लिए निर्णय ले सकता है, हालांकि।
शादिनिजा

1
appendएक nilटुकड़ा करने के लिए आईएनजी हमेशा गो में काम किया है?
एलियाडिफरिया

@alediaferia कभी भी 1.0 जाने के बाद से निश्चित रूप से।
निक क्रेग-वुड

4

मैं अपने स्वयं के उद्देश्यों के लिए इस मुद्दे को थोड़ा देख रहा था; मेरे पास कुछ स्लाइस (कुछ बिंदुओं सहित) का टुकड़ा था और मैं यह सुनिश्चित करना चाहता था कि मुझे यह सही लगे; इस धागे पर समाप्त हुआ, और मेरे परिणामों को साझा करना चाहता था।

अभ्यास करने के लिए, मैंने थोड़ा खेल का मैदान बनाया: https://play.golang.org/p/9i4gPx3lnY

जो इस के लिए:

package main

import "fmt"

type Blah struct {
    babyKitten int
    kittenSays *string
}

func main() {
    meow := "meow"
    Blahs := []Blah{}
    fmt.Printf("Blahs: %v\n", Blahs)
    Blahs = append(Blahs, Blah{1, &meow})
    fmt.Printf("Blahs: %v\n", Blahs)
    Blahs = append(Blahs, Blah{2, &meow})
    fmt.Printf("Blahs: %v\n", Blahs)
    //fmt.Printf("kittenSays: %v\n", *Blahs[0].kittenSays)
    Blahs = nil
    meow2 := "nyan"
    fmt.Printf("Blahs: %v\n", Blahs)
    Blahs = append(Blahs, Blah{1, &meow2})
    fmt.Printf("Blahs: %v\n", Blahs)
    fmt.Printf("kittenSays: %v\n", *Blahs[0].kittenSays)
}

उस कोड को जैसे-जैसे चल रहा है, वैसे ही "म्याऊ" और "म्याऊ 2" चर दोनों के लिए समान स्मृति पता दिखाया जाएगा:

Blahs: []
Blahs: [{1 0x1030e0c0}]
Blahs: [{1 0x1030e0c0} {2 0x1030e0c0}]
Blahs: []
Blahs: [{1 0x1030e0f0}]
kittenSays: nyan

जो मुझे लगता है कि यह पुष्टि करता है कि संरचना कचरा एकत्र है। विचित्र रूप से पर्याप्त, टिप्पणी की गई प्रिंट लाइन को अनसुना करते हुए, मेवों के लिए अलग-अलग मेमोरी एड्रेस प्राप्त होंगे:

Blahs: []
Blahs: [{1 0x1030e0c0}]
Blahs: [{1 0x1030e0c0} {2 0x1030e0c0}]
kittenSays: meow
Blahs: []
Blahs: [{1 0x1030e0f8}]
kittenSays: nyan

मुझे लगता है कि यह किसी तरह से प्रिंट ()? में स्थगित होने के कारण हो सकता है, लेकिन कुछ मेमोरी एमजीएमटी व्यवहार का दिलचस्प चित्रण, और एक और वोट के लिए:

[]MyStruct = nil

अच्छे विस्तृत उदाहरण हैं। धन्यवाद!
डोलनोर

2
यह meo1 और meow2 के मेमोरी पतों को समान नहीं दिखाता है: (पूर्व में समाप्त होता है , बाद में ) के 0x1030e0c0बराबर नहीं है । 0x1030e0f0c0f0
कार्बोकेशन

यहाँ @carbocation से सहमत होने के लिए, वे मेमोरी एड्रेस समान नहीं हैं। मैं यहाँ क्या चल रहा है, इसे बेहतर ढंग से समझाने में सक्षम होने का दावा नहीं करता, लेकिन यह मेरे लिए सबूत के रूप में काम नहीं करता है। मैं meow2प्रत्येक रन के पते में एक ही 8-बाइट विसंगति
देखता हूं
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.