2012-10-27 16 views
6

C'è il tipo Company, che è una struttura, contenente una mappa di Person, che sono anche tutte le strutture.Chiamare un metodo puntatore su una struttura in una mappa

type Company struct { 
    employees map[int]Person 
} 

type Person struct { 
    [...] 
} 

Dopo aver assegnato alcune persone alla mappa dipendenti, sto provando a chiamare un metodo puntatore su ognuna di queste.

func (company *Company) Populate(names []string) { 
    for i := 1; i <= 15; i++ { 
     company.employees[i] = Person{names[i - 1], [...]} 
     company.employees[i].Initialize() 
    } 
} 

fallisce miseramente Questo, con il go-compilatore lamentarsi che non posso chiamare i metodi puntatore su company.employees [i], così come non posso prendere l'indirizzo del company.employees [i]. Tuttavia, l'impostazione della inizializzazione-metodo per un metodo non puntatore e lasciandolo restituire la copia della persona, e l'assegnazione alla mappa nuovamente utilizzando

company.employees[i] = company.employees[i].Initialize() 

opere, che non è quello diverso.

Non avendo mai lavorato con i puntatori, questo mi dà fastidio. Le mappe non sono immutabili e vengono modificate in entrambi i casi, quindi chiamare un metodo puntatore su un'entità in una mappa non dovrebbe essere un problema, almeno nella mia testa.

Se qualcuno potesse spiegarmi cosa sto facendo male qui - o correggere il mio pensiero - sarei lieto.

risposta

11

Il problema è che per chiamare un metodo puntatore, l'indirizzo di employees[i] deve essere presa. In base allo Go specification:

L'operando deve essere indirizzabile, ovvero una variabile, puntatore indiretto o operazione di indicizzazione delle sezioni; o un selettore di campo di un operando struct indirizzabile; o un'operazione di indicizzazione dell'array di un array indirizzabile. Come eccezione al requisito di indirizzabilità, x può anche essere un letterale composito.

Un'operazione di indicizzazione della mappa non è indirizzabile. Ciò è stato deciso in modo che le implementazioni cartografiche non avessero bisogno di garantire che gli indirizzi dei valori non cambiassero. Man mano che più dati vengono aggiunti alla mappa, è possibile ricollocare i dati per motivi di efficienza.

Quindi, come si può risolvere? Se si dispone di un map[int]*Person, non sarà necessario prendere l'indirizzo dei dati nella mappa poiché il valore della mappa è già un indirizzo.

Un ultimo consiglio, Person.Initialize() non è un codice Go molto idiomatico. Se è necessario inizializzare un tipo, si utilizza normalmente una funzione NewPerson(). La funzione NewPerson() restituirebbe una struct o un puntatore Person inizializzato.

+1

Grazie mille per averlo chiarito. Ho seguito entrambi i vostri suggerimenti e rimosso il metodo Initialize (sebbene fosse comunque solo un nome temporaneo) e ho creato una funzione NewPerson() contenente quel bit di codice e restituendo una persona inizializzata. Uso di un indirizzamento di mappe I puntatori di persona hanno generato meno e - insieme a NewPerson() - codice più comprensibile. –

0

Ad esempio,

package main 

import "fmt" 

type Person struct { 
    Name string 
} 

func NewPerson(name string) *Person { 
    return &Person{Name: name} 
} 

type Company struct { 
    Employees map[int]*Person 
} 

func (c *Company) Populate(names []string) { 
    c.Employees = make(map[int]*Person) 
    for i := range names { 
     c.Employees[i+1] = NewPerson(names[i]) 
    } 
} 

func main() { 
    c := Company{} 
    c.Populate([]string{"Peter", "Paul"}) 
    for k, v := range c.Employees { 
     fmt.Println(k, *v) 
    } 
} 

uscita:

1 {Peter} 
2 {Paul} 
Problemi correlati