Qual a diferença de usar um receiver com ou sem ponteiro em Go?
Tags: go, receiver, ponteiro, defer
Published: 2023-09-25 12:52:41

---
title: Qual a diferença de usar um receiver com ou sem ponteiro em Go?
published: true
description: Ao trabalhar com Go, você pode ter se deparado com a decisão de usar um receiver com ou sem um ponteiro em métodos. Vamos explorar essa escolha fundamental na linguagem Go usando um exemplo simples de código. E no final, ainda vou compartilhar um detalhe bônus sobre o uso do defer.
tags: go, receiver, ponteiro, defer
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-09-24 16:53 +0000
---

Recentemente, tive a incrível oportunidade de participar de um dos maiores eventos de [Golang](https://go.dev/) da América Latina, a [Gophercon BR](https://gopherconbr.org/). Gostaria de expressar minha gratidão aos organizadores e a todos que estiveram presentes no evento, pois proporcionaram um ambiente incrível para networking e aprendizado.

Durante o evento, tive um encontro interessante com um rapaz chamado [João Salvador](https://www.linkedin.com/in/joao-salvador-rizzo/). Ele apresentou um desafio intrigante, exibindo um código que imediatamente despertou minha curiosidade e fez meus neurônios entrarem em ação para decifrá-lo. A experiência de resolver esse desafio foi estimulante e educativa, e, após concluí-lo, senti a necessidade de compartilhar esse conhecimento com a comunidade.

Neste post, estou entusiasmado em apresentar o desafio proposto por João Salvador e explicar os detalhes por trás dele. Acredito que a compreensão deste desafio trará uma nova perspectiva sobre o uso de receivers com ou sem ponteiro em Go, proporcionando insights valiosos que podem expandir nossos horizontes e ajudar muitas pessoas a aprofundar seu entendimento da linguagem.

---

### Desafio que me foi Apresentado no Evento
O que você espera que o console imprima? Pense bem antes de continuar lendo, isso vai enriquecer ainda mais sua compreensão no tópico em questão

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yssd1dij64xzc0sg4rgk.png)

Comente a sua resposta!

---

### Agora iremos juntos entender e desvendar a solução
Vamos começar nossa jornada entendendo que temos uma estrutura chamada "Person". Cada instância dessa estrutura possui um atributo chamado "Name", que armazena o nome de uma pessoa. Além disso, esta estrutura é enriquecida com um método chamado "SayHi", que é acionado por meio de um conceito conhecido como "receiver". A função principal deste método é simples, ele imprime na tela uma saudação, "Hi", seguida pelo nome da pessoa.

```go
// Declarada a estrutura Person
type Person struct {
	Name string
}

// SayHi vai printar uma saudação Hi seguida com o nome da pessoa
func (e Person) SayHi() {
	fmt.Printf("Hi %s!\n", e.Name)
}
```

### Tá! Mas o que é receiver?
É um parâmetro especial em um método de um tipo definido pelo usuário (struct) que permite que esse método seja chamado em instâncias desse tipo. O receiver é semelhante ao conceito de um objeto em orientação a objetos, mas é específico para métodos em Go.

Observamos que o método `SayHi` utiliza um receiver de valor, o que significa que, nesse contexto, o método atua em uma cópia do valor original do tipo. Isso implica que qualquer alteração efetuada dentro do método não terá efeito sobre a instância original desse tipo.

Agora que entendemos isso vamos ver como funciona um `receiver` de ponteiro. Ou seja, o método opera diretamente na instância original do tipo, pois recebe um ponteiro para ela. Isso permite que o método modifique o valor da instância original.
```go
func (p *Person) UpdateName(newName string) {
    p.Name = newName
}
```

Agora que entendemos ambos os casos comentado a cima, vamos criar nossa `func main()` para visualizar e entender os outputs gerados.

```go
func main() {
	var p = Person{Name: "Renan"}
	defer p.SayHi()              // Output: Hi Renan!
	defer func() { p.SayHi() }() // Output: Hi Renan Bastos!

	p.UpdateName("Renan Bastos")
}
```

Parece bruxaria mas não é, os dois `defer` imprimiram valores diferentes porque o defer empilha uma cópia da estrutura no primeiro e uma função anônima no segundo. Portanto, quando o defer é executado, ele já capturou a alteração no campo Name. O defer funciona como uma pilha, executando o último defer chamado primeiro e desempilhando conforme cada um é executado.

```go
// Output final
// Output: Hi Renan Bastos!
// Output: Hi Renan!
```

## Conclusão
Neste artigo, exploramos o conceito de receiver em Go e a utilidade do defer. Uma questão frequente é quando devemos optar por usar um receiver de ponteiro. A escolha depende das necessidades específicas de seu programa e do comportamento desejado, e não existe uma resposta única. Portanto, a melhor abordagem é avaliar cuidadosamente o contexto de seu código e escolher entre receiver de valor ou de ponteiro com base nas exigências do projeto.