2013-06-06 3 views
75

Каким образом можно очистить фрагмент в Go?Как очистить кусочек в Go?

Вот что я нашел в go forums:

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

Правильно ли это?

Чтобы уточнить, буфер очищается, поэтому его можно использовать повторно.

Пример: 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) } 
+1

быстрый тест на: http://play.golang.org/p/6Z-qDQtpbg, кажется, предполагает, что он будет работать (не будет изменять мощность, но будет усекать длину) –

ответ

72

Все зависит от того, что ваше определение 'ясно'. Одним из действительных, безусловно, является:

slice = slice[:0] 

Но есть улов. Если ломтик элементы типа Т:

var slice []T 

тогда исполнение len(slice) равного нуль, приведенным выше «трюк», не сделать какой-либо элемент

slice[:cap(slice)] 

приемлемого для сбора мусора. Это может быть оптимальный подход в некоторых сценариях. Но это также может быть причиной «утечек памяти» - память не используется, но потенциально доступна (после повторной нарезки «среза») и, следовательно, не мусор «коллекционируется».

+0

Интересно. Есть ли другой способ удалить все элементы из основного массива среза, оставив базовую емкость без изменений? –

+3

@ChrisWeber: просто перебирайте базовый массив и установите все элементы в новое значение. – newacct

+0

@newacct, спасибо, я догадывался об этом. –

122

Настройка ломтика на nil - лучший способ очистить фрагмент. nil ломтики в ходу отлично себя ведут, и установка среза на nil освободит базовую память сборщика мусора.

See playground

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

Ник спасибо за ответ. Пожалуйста, посмотрите мое обновление, которое вы хотели бы. Я очищаю ломтик для повторного использования. Поэтому я не обязательно хочу, чтобы базовая память была выпущена в GC, так как мне просто нужно будет выделить ее снова. –

+0

это то, что я искал!) –

+3

Основано на названии «Как вы очистите кусочек в Go?» это далеко и далеко более безопасный ответ и должен быть принят. Идеальный ответ был бы сочетанием первоначально принятого ответа и этого, чтобы люди могли сами решить. – Shadoninja

4

Я изучал этот вопрос немного для своих целей; У меня был фрагмент структур (включая некоторые указатели), и я хотел убедиться, что я понял это правильно; закончил эту тему и хотел поделиться своими результатами.

Практиковать, я сделал немного идти площадка: https://play.golang.org/p/9i4gPx3lnY

который Evals к этому:

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

Запуск этого кода как есть будет показывать один и тот же адрес памяти для обоих «мяу» и переменные «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 
+0

Приятные подробные примеры. Благодаря! – Dolanor

Смежные вопросы