Skip to content

Ponteiros do Go

Go manteve os ponteiros, garantindo até certo ponto a performance, ao mesmo tempo em que limitou o uso de ponteiros para melhor GC e segurança.

Criação

Sobre ponteiros existem dois operadores comumente usados, um é o operador de endereço &, o outro é o operador de desreferenciação *. Ao obter o endereço de uma variável, retorna-se um ponteiro do tipo correspondente, por exemplo

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

O ponteiro armazena o endereço da variável num

0xc00001c088

O operador de desreferenciação tem dois usos, o primeiro é acessar o elemento para o qual o ponteiro aponta, ou seja, desreferenciação, por exemplo

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

p é um ponteiro, ao desreferenciar o tipo ponteiro pode-se acessar o elemento para o qual o ponteiro aponta. Outro uso é declarar um ponteiro, por exemplo

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

*int significa que o tipo dessa variável é um ponteiro do tipo int, mas o ponteiro não pode apenas ser declarado, também precisa ser inicializado, precisa-se alocar memória para ele, caso contrário é um ponteiro nulo, não pode ser usado normalmente. Ou se usa o operador de endereço para atribuir o endereço de outra variável a esse ponteiro, ou se usa a função incorporada new para alocar manualmente, por exemplo

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

Mais comum é usar declaração curta de variável

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

A função new tem apenas um parâmetro que é o tipo, e retorna um ponteiro do tipo correspondente, a função vai alocar memória para esse ponteiro, e o ponteiro aponta para o valor zero do tipo correspondente, por exemplo

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]
[]

Operações com Ponteiros Proibidas

Em Go não há suporte para operações com ponteiros, ou seja, o ponteiro não pode ser deslocado, primeiro vejamos um código 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

Pode-se ver que o endereço do array é consistente com o endereço do primeiro elemento do número, e após a operação de adição de um ao ponteiro, o elemento para o qual ele aponta é o segundo elemento do array. Arrays em Go também são assim, mas a diferença é que o ponteiro não pode ser deslocado, por exemplo

go
func main() {
   arr := [5]int{0, 1, 2, 3, 4}
   p := &arr
   println(&arr[0])
   println(p)
   // tentando fazer operação com ponteiro
   p++
   fmt.Println(p)
}

Esse programa não vai compilar, com o seguinte erro

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

TIP

A biblioteca padrão unsafe fornece muitas operações para programação de baixo nível, incluindo operações com ponteiros, vá para biblioteca padrão - unsafe para entender os detalhes.

new e make

Nas seções anteriores já mencionamos muitas vezes as funções incorporadas new e make, ambos são um pouco similares, mas também têm diferenças, vamos revisar abaixo.

go
func new(Type) *Type
  • O valor de retorno é um ponteiro do tipo
  • O parâmetro recebido é o tipo
  • Especificamente usado para alocar espaço de memória para ponteiros
go
func make(t Type, size ...IntegerType) Type
  • O valor de retorno é o valor, não um ponteiro
  • O primeiro parâmetro recebido é o tipo, parâmetros de comprimento variável são diferentes dependendo do tipo passado
  • Especificamente usado para alocar memória para slices, mapas e canais

Alguns exemplos abaixo

go
new(int) // ponteiro de int
new(string) // ponteiro de string
new([]int) // ponteiro de slice de inteiros
make([]int, 10, 100) // slice de inteiros com comprimento 10 e capacidade 100
make(map[string]int, 10) // mapa com capacidade 10
make(chan int, 10) // canal com tamanho de buffer 10

Golang por www.golangdev.cn edit