2013-06-03 9 views
7

http://play.golang.org/p/j-Y0mQzTdPCome preallocare e riempire una porzione di puntatori in modo go-idiomatico?

package main 

import "fmt" 

type UselessStruct struct { 
    a int 
    b int 
} 

func main() { 
    mySlice := make([]*UselessStruct, 5) 
    for i := 0; i != 5; i++ { 
     mySlice = append(mySlice, &UselessStruct{}) 
    } 

    fmt.Println(mySlice) 
} 

Uscite: [<nil> <nil> <nil> <nil> <nil> 0xc010035160 0xc010035170 0xc010035180 0xc010035190 0xc0100351a0]

Quello che vorrei fare, è la memoria Preallocare per 5 UselessStructs, memorizzati come puntatori. Se dichiaro una fetta di valori struct eq:

mySlice := make([]UselessStruct, 5) 

allora questo crea 5 vuote struct - apposizione non sostituisce la struct vuoti, ma piuttosto mantiene sull'aggiunta alla porzione, in modo che il risultato finale con questo codice:

http://play.golang.org/p/zBYqGVO85h

package main 

import "fmt" 

type UselessStruct struct { 
    a int 
    b int 
} 

func main() { 
    mySlice := make([]UselessStruct, 5) 
    for i := 0; i != 5; i++ { 
     mySlice = append(mySlice, UselessStruct{}) 
    } 

    fmt.Println(mySlice) 
} 

è: [{0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0}]

Qual è il modo in cui il go-idiomatica a preallocare e riempire fette?

risposta

17

Per il vostro primo esempio, lo farei:

mySlice := make([]*UselessStruct, 5) 
for i := range mySlice { 
    mySlice[i] = new(UselessStruct) 
} 

Il problema che si trovano ad affrontare in entrambi gli esempi è che si sta aggiungere i dati ad una fetta che è già la lunghezza corretta. Se si imposta mySlice := make([]*UselessStruct, 5), si richiede una porzione di puntatori nil di lunghezza 5. Se si aggiunge un puntatore, ora ha lunghezza 6.

Invece, si desidera utilizzare mySlice := make([]*UselessStruct, 0, 5). Questo crea una porzione di lunghezza 0 ma la capacità 5. Ogni volta che lo aggiungi ne aggiungi uno alla lunghezza, ma non verrà riallocato fino a quando non superi la capacità della sezione.

mySlice := make([]*UselessStruct, 0, 5) 
for i := 0; i != 5; i++ { 
    mySlice = append(mySlice, &UselessStruct{}) 
} 
// mySlice is [0xc010035160 0xc010035170 0xc010035180 0xc010035190 0xc0100351a0] 

Entrambi i miei esempi funzionerà come ci si aspetta, ma vi consiglio il primo per ragioni puramente di stile.

3

Sei sicuro di aver bisogno di indicazioni? La vostra struct ha un valore pari a zero così:

mySlice := make([]UselessStruct, 5) # has memory preallocated for 5 UselessStructs. 

E dal momento che le fette sono tipi di riferimento si ha effettivamente 5 puntatori a quei 5 UselessStructs.

Se avete bisogno di ottenere un riferimento a uno struct individuo a passare intorno allora si può solo così

myStruct := &mySlice[0] 

E ora avete un puntatore ad un UseLessStruct da utilizzare come meglio credi. È molto meno codice di quello che hai e sfrutta la funzione di valore zero di Go.

7

Ci sono due modi per farlo. Uno è pre-allocando gli slot come hai fatto tu. Ma invece di usare append, è sufficiente indice in uno degli slot esistenti:

mySlice[i] = &UselessStruct{} 

Il secondo è quello di utilizzare il verion 'sovraccarico' di make. Si specifica lunghezza zero, ma una capacità di 5.

package main 

type T struct { 
    A int 
    B int 
} 

func main() { 
    mySlice := make([]*T, 0, 5) 
    for i := 0; i < 5; i++ { 
     mySlice = append(mySlice, &T{1, 2}) 
    } 
} 

mySlice := make([]*T, 0, 5) inizializza la fetta con una lunghezza pari a zero, ma ancora pre-alloca spazio sufficiente per 5 voci.

0

Solo per completare: append funziona con zero slice quindi, non è necessario creare la slice con make, è possibile semplicemente aggiungere un elemento ad esso.

var mySlice []*UselessStruct 
for i := 0; i < 5; i++ { 
    mySlice = append(mySlice, &UselessStruct{}) 
} 

questo farà la stessa dell'esempio precedente senza pre-allocazione, ma se si conosce la dimensione, si preferisce utilizzare qualcosa di simile a questo:

mySlice := make([]*UselessStruct, 0, 5) 
for i := range mySlice { 
    mySlice[i] = &UselessStruct{} 
} 

Questo può evitare alcuni riallocazione.

Problemi correlati