I puntatori sono utili per diversi motivi. I puntatori consentono il controllo sul layout della memoria (influisce sull'efficienza della cache della CPU). In Go possiamo definire una struttura in cui tutti i membri sono in memoria contigua:
type Point struct {
x, y int
}
type LineSegment struct {
source, destination Point
}
In questo caso le Point
strutture sono incorporate all'interno della LineSegment
struttura. Ma non puoi sempre incorporare i dati direttamente. Se vuoi supportare strutture come alberi binari o liste collegate, allora devi supportare un qualche tipo di puntatore.
type TreeNode {
value int
left *TreeNode
right *TreeNode
}
Java, Python ecc. Non hanno questo problema perché non consentono di incorporare tipi compositi, quindi non è necessario distinguere sintatticamente tra incorporamento e puntamento.
Problemi con le strutture Swift / C # risolti con i puntatori Go
Una possibile alternativa per ottenere lo stesso risultato è distinguere tra struct
e class
come fa C # e Swift. Ma questo ha dei limiti. Sebbene di solito sia possibile specificare che una funzione accetta una struttura come inout
parametro per evitare di copiare la struttura, non consente di memorizzare riferimenti (puntatori) a strutture. Ciò significa che non puoi mai trattare una struttura come un tipo di riferimento quando lo trovi utile, ad esempio per creare un allocatore di pool (vedi sotto).
Allocatore di memoria personalizzato
Usando i puntatori puoi anche creare il tuo allocatore di pool (questo è molto semplificato con molti controlli rimossi per mostrare solo il principio):
type TreeNode {
value int
left *TreeNode
right *TreeNode
nextFreeNode *TreeNode; // For memory allocation
}
var pool [1024]TreeNode
var firstFreeNode *TreeNode = &pool[0]
func poolAlloc() *TreeNode {
node := firstFreeNode
firstFreeNode = firstFreeNode.nextFreeNode
return node
}
func freeNode(node *TreeNode) {
node.nextFreeNode = firstFreeNode
firstFreeNode = node
}
Scambia due valori
I puntatori ti consentono anche di implementare swap
. Ovvero scambiare i valori di due variabili:
func swap(a *int, b *int) {
temp := *a
*a = *b
*b = temp
}
Conclusione
Java non è mai stato in grado di sostituire completamente il C ++ per la programmazione di sistemi in luoghi come Google, in parte perché le prestazioni non possono essere regolate nella stessa misura a causa della mancanza di capacità di controllare il layout e l'utilizzo della memoria (i mancati riscontri nella cache influiscono in modo significativo sulle prestazioni). Go ha mirato a sostituire il C ++ in molte aree e quindi deve supportare i puntatori.