Os ponteiros são úteis por vários motivos. Os ponteiros permitem o controle sobre o layout da memória (afeta a eficiência do cache da CPU). Em Go podemos definir uma estrutura onde todos os membros estão em memória contígua:
type Point struct {
x, y int
}
type LineSegment struct {
source, destination Point
}
Nesse caso, as Point
estruturas são incorporadas à LineSegment
estrutura. Mas você nem sempre pode incorporar dados diretamente. Se você deseja oferecer suporte a estruturas como árvores binárias ou lista vinculada, você precisa oferecer suporte a algum tipo de ponteiro.
type TreeNode {
value int
left *TreeNode
right *TreeNode
}
Java, Python etc. não tem esse problema porque não permite que você insira tipos compostos, portanto, não há necessidade de diferenciar sintaticamente entre embutir e apontar.
Problemas com estruturas Swift / C # resolvidos com ponteiros Go
Uma alternativa possível para fazer o mesmo é diferenciar entre struct
e class
como fazem C # e Swift. Mas isso tem limitações. Embora geralmente você possa especificar que uma função recebe uma estrutura como inout
parâmetro para evitar a cópia da estrutura, isso não permite que você armazene referências (ponteiros) para estruturas. Isso significa que você nunca pode tratar uma estrutura como um tipo de referência quando achar isso útil, por exemplo, para criar um alocador de pool (veja abaixo).
Alocador de memória personalizado
Usando ponteiros, você também pode criar seu próprio alocador de pool (isso é muito simplificado com muitas verificações removidas apenas para mostrar o princípio):
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
}
Trocar dois valores
Ponteiros também permitem que você implemente swap
. Isso é trocar os valores de duas variáveis:
func swap(a *int, b *int) {
temp := *a
*a = *b
*b = temp
}
Conclusão
Java nunca foi capaz de substituir totalmente C ++ para programação de sistemas em locais como o Google, em parte porque o desempenho não pode ser ajustado para a mesma extensão devido à falta de capacidade de controlar o layout e o uso da memória (falhas de cache afetam o desempenho significativamente). Go tem como objetivo substituir C ++ em muitas áreas e, portanto, precisa oferecer suporte a ponteiros.