2015-09-10 26 views
7

Go non permette di prendere l'indirizzo di un membro di mappa:Perché non proibire di prendere l'indirizzo di (&) membro della mappa, ma consente l'elemento (&) slice?

// if I do this: 
p := &mm["abc"] 
// Syntax Error - cannot take the address of mm["abc"] 

La logica è che se Go permette di prendere questo indirizzo, quando la mappa interni del supermercato cresce o shinks, l'indirizzo può diventare valido, confondere l'utente .

Ma Vai fetta viene trasferita quando diventa troppo grande per la sua capacità, tuttavia, Go ci permette di prendere l'indirizzo di un elemento fetta:

a := make([]Test, 5) 
a[0] = Test{1, "dsfds"} 
a[1] = Test{2, "sdfd"} 
a[2] = Test{3, "dsf"} 

addr1 := reflect.ValueOf(&a[2]).Pointer() 
fmt.Println("Address of a[2]: ", addr1) 

a = append(a, Test{4, "ssdf"}) 
addrx := reflect.ValueOf(&a[2]).Pointer() 
fmt.Println("Address of a[2] After Append:", addrx) 

// Note after append, the first address is invalid 
Address of a[2]: 833358258224 
Address of a[2] After Append: 833358266416 

Perché Go progettato come questo? Cosa c'è di speciale nel prendere l'indirizzo dell'elemento slice?

+3

Leggi questo: [Vai: le matrici e le mappe devono essere concetti/caratteristiche diverse?] (Http://stackoverflow.com/questions/25294290/go-do-arrays-and-maps-have-to-be -differenti-concetti-funzioni) – icza

+2

Sfortunatamente, nulla è speciale riguardo al prendere l'indirizzo di un elemento slice - se continui ad usare quel primo indirizzo dopo che lo slice cresce (piuttosto che eseguire il codice '& a [2]' again post-' append', come stai facendo), avrai ancora puntatori nel vecchio array, quindi non puoi usarlo per vedere o fare aggiornamenti al nuovo array, e il vecchio array è ancora raggiungibile e quindi non garbage- da collezione. L'indirizzo di correzione – twotwotwo

+0

per la mappa è più difficile che correggere l'indirizzo per l'array, penso. –

risposta

10

C'è una grande differenza tra fette e mappe: le fette sono supportate da un backing array e le mappe no.

Se una mappa aumenta o riduce un potenziale puntatore a un elemento di una mappa può diventare un puntatore pendente che punta verso il nulla (memoria non inizializzata). Il problema qui non è "confusione dell'utente", ma che potrebbe rompere un importante elemento di design di Go: nessun puntatore penzolante.

Se una sezione esaurisce la capacità viene creato un nuovo array di supporto più grande e il vecchio array di supporto viene copiato nel nuovo; e il vecchio array di supporto rimaneesistente. Pertanto, qualsiasi puntatore ottenuto dalla porzione "non coperta" che punta nel vecchio array di supporto è ancora un valido riferimento alla memoria valida.

Se si dispone ancora di una sezione che punta al vecchio array di supporto (ad esempio perché è stata eseguita una copia della sezione prima di aumentare la sezione oltre la sua capacità), si accede ancora al vecchio array di supporto. Ciò ha meno a che fare con i puntatori degli elementi della sezione, ma le sezioni sono viste in matrici e gli array che vengono copiati durante la crescita delle fette.

Si noti che non esiste "la riduzione dell'array di supporto di una sezione" durante il ritiro delle fette.

+0

Grazie! Che ne dici dei campi struct? Posso prendere l'indirizzo di un campo come questo: 'ptr: = & (object.Field1)', ma quando provo a far riflettere l'indirizzo, 'CanAddr()' return false: ho provato 'reflect.ValueOf (oggetto) .FieldByName ("Field1"). CanAddr() 'e' reflect.ValueOf (& object) .Elem(). FieldByName ("Field1"). CanAddr() ', entrambi restituiscono false. Perché? – NeoWang

+1

@NeoWang: perché stai passando il valore dell'oggetto da riflettere. Puoi fare un'altra domanda separata se ancora non capisci; non è correlato a mappe o sezioni. – JimB