[arrays] Go에서 슬라이스를 어떻게 지우나요?

Go에서 슬라이스를 지우는 적절한 방법은 무엇입니까?

다음은 go 포럼 에서 찾은 내용입니다 .

// 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))
}

이 올바른지?

명확히하기 위해 버퍼를 지워 재사용 할 수 있습니다.

예는 bytes 패키지의 Buffer.Truncate 함수입니다.

Reset은 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) }



답변

그것은 모두 당신의 ‘명확한’정의에 달려 있습니다. 유효한 것 중 하나는 확실히 다음과 같습니다.

slice = slice[:0]

하지만 문제가 있습니다. 슬라이스 요소가 T 유형 인 경우 :

var slice []T

다음 시행 len(slice)은 “트릭”이상으로, 제로로, 하지 의 요소를 만들

slice[:cap(slice)]

가비지 수집 대상입니다. 이는 일부 시나리오에서 최적의 접근 방식 일 수 있습니다. 그러나 이것은 또한 “메모리 누수”의 원인이 될 수 있습니다. 메모리는 사용되지 않지만 잠재적으로 도달 할 수 있으며 ( ‘슬라이스’재분할 후) 가비지 “수집 가능”이 아닙니다.


답변

슬라이스를 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은 해당 별칭을 제거합니다.

이 방법은 용량을 0으로 변경합니다.


답변

나는 내 목적을 위해이 문제를 약간 조사하고 있었다. 나는 구조체 조각 (포인터 포함)을 가지고 있었고 제대로 된 것인지 확인하고 싶었다. 이 스레드에 올랐고 결과를 공유하고 싶었습니다.

연습을 위해 약간의 운동장을 사용했습니다 :
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)
}

해당 코드를있는 그대로 실행하면 “meow”및 “meow2″변수에 대해 동일한 메모리 주소가 동일한 것으로 표시됩니다.

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


답변