Usando Ponteiros em Go
Desde os primórdios da era da computação, sempre existiu e ainda existe, um assunto bastante interessante sobre a forma como nossos dados são criados e passados a diante durante a execução do nosso sistema.
Assuntos como esses eram de vitais importância quando o professor entrava no assunto sobre gerenciamento de memória.
Hoje, pretendo explicar para você o que vem a ser um ponteiro e como utilizá-los em Go. Vamos nessa?
O que são ponteiros?

"Ponteiro é aquele que aponta para alguma coisa, que mostra um caminho a ser seguido." - William Lima, 2025.
Partindo desse princípio, creio que fica mais fácil o entendimento sobre o que vem a ser um ponteiro no mundo da TI.
Eles nada mais são do que variáveis especiais em linguagens de programação que armazenam o endereço de memória de outra variável.
Em vez de guardar diretamente um valor, um ponteiro aponta para a localização onde esse valor está armazenado na memória do computador.
E isso também diz a respeito que toda variável que nós criamos, é salva dentro de um endereço de memória do nosso computador.
Neste caso, um ponteiro nada mais é do que uma espécie de aplicativo de atalho do windows.
Se você nunca usou o sistema operacional Windows, saiba que o que mais se vê dentro dele, são ícones de aplicativos, que representam atalhos para um aplicativo principal, que esta armazenado de forma interna no sistema.
Tanto é que, se se você clicar e arrastar esse atalho para um pen drive, ou até mesmo para a nuvem, o que é copiado é apenas um atalho, e não a aplicação de fato.
Sendo assim, podemos dizer que um ponteiro é como se fosse um aplicativo de atalho do windows, ou seja, ele não contém o dado em si, somente um apontamento para onde o dado está de fato armazenado.
🧠 Conceito básico de ponteiros
Imagine a memória do computador como uma série de "caixinhas" numeradas, onde cada número representa um endereço. Um ponteiro é como um bilhete com um desses números, indicando onde encontrar um valor.

O uso de ponteiros trás consigo uma série de benefícios, tais como:
Eficiência: Permite manipular grandes estruturas de dados (como arrays ou objetos) sem copiá-los.
Referência direta: Permite modificar valores diretamente em memória.
Compartilhamento de dados: Facilita o compartilhamento de informações entre diferentes partes do programa.
Estruturas complexas: Usado para implementar listas encadeadas, árvores e outras estruturas de dados dinâmicas.
Dito isso, creio que você já tem o entendimento suficiente para seguirmos com a criação de ponteiros em Go, certo? 😉
Criando seu projeto de testes
Dentro da pasta JornadaGoLang, nós iremos criar uma nova pasta chamada de 13-ponteiros-em-go
, onde dentro dela, vamos criar o nosso arquivo main.go
:
package main
func main(){
}
Agora sim, vamos aprender a criar ponteiros! 😉
Criando ponteiros em Go
A criação de ponteiros no linguagem GoLang, é uma das coisas mais simples de tudo que já vimos até agora, observe:
package main
import "fmt"
func main() {
x := 10
p := &x // 'p' é um ponteiro para 'x'
}
Observe que criamos uma variável chamada x
que armazena o valor 10
. Em seguida criamos uma outra variável chamada p
que armazena o valor de x
(que é igual a 10).
A única diferença é que adicionamos o &
antes do x
. O que significa que a variável p
não armazena o valor 10
, mas sim, aponta para a variável x
.
Resumindo, a variável p
é um ponteiro que aponta para x
.
Inicialmente, não tem nada demais com isso, certo?
Agora experimente só mudar o valor de p
achando que o x
não irá mudar 😂
É obvio que ele vai mudar, olhe só:
package main
import "fmt"
func main() {
x := 10
p := &x // 'p' é um ponteiro para 'x'
fmt.Println("Valor de x:", x) // Saída: 10
fmt.Println("Endereço de x:", p) // Saída: endereço de memória
fmt.Println("Valor via ponteiro:", *p) // Saída: 10
*p = 20 // Modifica o valor de 'x' através do ponteiro
fmt.Println("Novo valor de x:", x) // Saída: 20
}
Note que ao mostrarmos o valor de p
de forma pura, o retorno será um endereço de memória. Para contornar isso, basta usar o comando *
antes da variável p
, para que o compilador pegue o valor 10
.
&x:
Captura o endereço de memória dex
.p
: Armazena o endereço dex
.*p
: Desreferencia o ponteiro, ou seja, acessa o valor armazenado no endereço.
Por que usar ponteiros em Go?
Em Go, os ponteiros são úteis quando você deseja manipular dados de forma mais eficiente, evitar cópias desnecessárias e compartilhar informações entre diferentes partes do programa.
Vejamos abaixo, algumas situações em que os ponteiros podem ser úteis:
📌 Modificar valores diretamente
Quando você passa uma variável para uma função em Go, ela é passada por valor (uma cópia é criada). Se você precisar modificar o valor original, precisa usar um ponteiro.
✅ Exemplo sem ponteiro (não altera o valor original):
package main
import "fmt"
func dobrarValor(n int) {
n = n * 2
}
func main() {
num := 10
dobrarValor(num)
fmt.Println("Sem ponteiro:", num) // Saída: 10 (não mudou)
}
✅ Exemplo com ponteiro (altera o valor original):
package main
import "fmt"
func dobrarValor(n *int) {
*n = *n * 2
}
func main() {
num := 10
dobrarValor(&num)
fmt.Println("Com ponteiro:", num) // Saída: 20 (mudou!)
}
Observação: num
pega o endereço de memória da variável num
, e *n
acessa/modifica o valor nesse endereço.
📌 Melhorar a eficiência com grandes estruturas
Se você tem uma estrutura grande (como um struct), passar um ponteiro evita criar uma cópia inteira, economizando memória e processamento.
package main
import "fmt"
type Produto struct {
Nome string
Preco float64
}
func aplicarDesconto(p *Produto) {
p.Preco -= 10
}
func main() {
p := Produto{"Notebook", 3500}
aplicarDesconto(&p)
fmt.Println("Preço com desconto:", p.Preco) // Saída: 3490
}
Observação: Passar o ponteiro evita copiar todo o struct
, tornando o código mais rápido.
📌 Trabalhar com nil para representar ausência de valor
Ponteiros podem ser nulos (nil
), o que permite representar a ausência de um valor ou estado não inicializado.
package main
import "fmt"
func getNome() *string {
return nil // Não há nome disponível
}
func main() {
nome := getNome()
if nome == nil {
fmt.Println("Nome não encontrado!")
}
}
📌 Compartilhar estado entre goroutines
Se várias goroutines
precisarem acessar e modificar uma variável, usar um ponteiro permite que todas compartilhem o mesmo valor na memória.
Em lições futuras, quando aprendermos sobre goroutines
, você irá usar muitos ponteiros para isso 😋
package main
import (
"fmt"
"sync"
)
func incrementar(contador *int, wg *sync.WaitGroup) {
defer wg.Done()
*contador++
}
func main() {
var wg sync.WaitGroup
contador := 0
for i := 0; i < 5; i++ {
wg.Add(1)
go incrementar(&contador, &wg)
}
wg.Wait()
fmt.Println("Valor final:", contador) // Saída: 5
}
Repositório da lição
Todos os arquivos relacionados com esta lição, podem ser encontrados nos seguintes repositórios abaixo:
Conclusão
Nesta lição, vimos apenas como criar ponteiros em GoLang!
Uma das lições mais importantes antes de aprendermos sobre goroutines
🙃