Skip to content

Puntatori Go

Go mantiene i puntatori, garantendo in una certa misura le prestazioni, e allo stesso tempo limita l'uso dei puntatori per un GC migliore e per considerazioni di sicurezza.

Creazione

Per i puntatori ci sono due operatori comunemente utilizzati: uno è l'operatore di indirizzo &, l'altro è l'operatore di dereferenziazione *. Prendendo l'indirizzo di una variabile, viene restituito un puntatore del tipo corrispondente. Ad esempio:

go
func main() {
   num := 2
   p := &num
   fmt.Println(p)
}

Il puntatore memorizza l'indirizzo della variabile num

0xc00001c088

L'operatore di dereferenziazione ha due scopi: il primo è accedere all'elemento puntato dal puntatore, ovvero dereferenziare. Ad esempio

go
func main() {
  num := 2
  p := &num
  rawNum := *p
  fmt.Println(rawNum)
}

p è un puntatore, dereferenziando il tipo puntatore è possibile accedere all'elemento puntato dal puntatore. L'altro scopo è dichiarare un puntatore. Ad esempio:

go
func main() {
   var numPtr *int
   fmt.Println(numPtr)
}
<nil>

*int significa che il tipo della variabile è un puntatore di tipo int. Tuttavia, i puntatori non possono essere solo dichiarati, devono anche essere inizializzati. È necessario allocare memoria per essi, altrimenti sono puntatori nulli e non possono essere utilizzati normalmente. O si utilizza l'operatore di indirizzo per assegnare l'indirizzo di un'altra variabile al puntatore, o si utilizza la funzione incorporata new per allocare manualmente. Ad esempio:

go
func main() {
   var numPtr *int
   numPtr = new(int)
   fmt.Println(numPtr)
}

Si utilizza più spesso la variabile breve

go
func main() {
   numPtr := new(int)
   fmt.Println(numPtr)
}

La funzione new ha un solo parametro, ovvero il tipo, e restituisce un puntatore del tipo corrispondente. La funzione allocherà memoria per il puntatore e il puntatore punterà al valore zero del tipo corrispondente. Ad esempio:

go
func main() {
   fmt.Println(*new(string))
   fmt.Println(*new(int))
   fmt.Println(*new([5]int))
   fmt.Println(*new([]float64))
}

0
[0 0 0 0 0]
[]

Operazioni con puntatori non supportate

In Go non sono supportate le operazioni con puntatori, ovvero i puntatori non possono essere spostati. Prima guarda un codice C++:

cpp
int main() {
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    int *p = &arr[0];
    cout << &arr << endl
         << p << endl
         << p + 1 << endl
         << &arr[1] << endl;
}
0x31d99ff880
0x31d99ff880
0x31d99ff884
0x31d99ff884

Si può vedere che l'indirizzo dell'array è coerente con l'indirizzo del primo elemento dell'array e, dopo aver aggiunto uno al puntatore, punta al secondo elemento dell'array. Anche gli array in Go sono così, ma la differenza è che i puntatori non possono essere spostati. Ad esempio

go
func main() {
   arr := [5]int{0, 1, 2, 3, 4}
   p := &arr
   println(&arr[0])
   println(p)
   // Tenta di eseguire operazioni con puntatori
   p++
   fmt.Println(p)
}

Questo tipo di programma non supererà la compilazione, l'errore è il seguente

main.go:10:2: invalid operation: p++ (non-numeric type *[5]int)

TIP

La libreria standard unsafe fornisce molte operazioni per la programmazione di basso livello, incluse le operazioni con puntatori. Visita Libreria standard-unsafe per i dettagli.

new e make

Nelle sezioni precedenti sono state menzionate molte volte le funzioni incorporate new e make. Le due sono simili, ma ci sono anche differenze. Di seguito una revisione.

go
func new(Type) *Type
  • Il valore di ritorno è un puntatore al tipo
  • Il parametro ricevuto è un tipo
  • Specializzato per allocare memoria per puntatori
go
func make(t Type, size ...IntegerType) Type
  • Il valore di ritorno è un valore, non un puntatore
  • Il primo parametro ricevuto è un tipo, i parametri di lunghezza variabile dipendono dal tipo passato
  • Specializzato per allocare memoria per slice, mappe e canali

Di seguito alcuni esempi:

go
new(int) // puntatore int
new(string) // puntatore string
new([]int) // puntatore a slice di interi
make([]int, 10, 100) // slice di interi con lunghezza 10, capacità 100
make(map[string]int, 10) // mappa con capacità 10
make(chan int, 10) // canale con buffer di dimensione 10

Golang by www.golangdev.cn edit