Parênteses estranhos antes do nome da função em Go: análise completa

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Parênteses estranhos antes do nome da função em Go: análise completa



Imagine: você abre um código Go de outra pessoa e vê algo que faz seu olho tremer:



func (u User) Greet() string {    return "Olá, " + u.Name}


Pare. O que é esse (u User) antes do nome da função? Em Python, para métodos, usamos def greet(self):, em Java — public String greet() dentro de uma classe. E aqui — uns parênteses, ainda mais com um tipo dentro. Loucura? Não, genial!



Essa construção é uma das funcionalidades mais poderosas do Go, que frequentemente confunde iniciantes. Na verdade, isso é um receiver (receptor) — a chave para entender a programação orientada a objetos em Go.



Neste artigo, vamos olhar por baixo do capô do compilador Go, analisar como esses parênteses funcionam e por que sem eles seu código parecerá dos anos 90. Pronto? Vamos lá!



O que é um receiver e para que serve?



Em Go, não existem classes no sentido clássico. Mas existem structs (estruturas) e métodos. Os parênteses antes do nome da função são exatamente a declaração de um método para um tipo específico. Tecnicamente, isso é chamado de receiver parameter.



A sintaxe é simples:

func (receiver_name ReceiverType) MethodName(params) return_type {    // corpo do método}


Aqui, receiver_name é uma variável através da qual você acessa os campos da struct (como self em Python ou this em Java). E ReceiverType é o seu tipo (geralmente uma struct).



Exemplo da vida real:

package main

import "fmt"

type User struct { Name string Age int}

// Método com receiverfunc (u User) SayHello() { fmt.Printf("Olá! Eu sou %s, tenho %d anos.", u.Name, u.Age)}

func main() { user := User{Name: "Alice", Age: 25} user.SayHello() // Saída: Olá! Eu sou Alice, tenho 25 anos.}


Observe: chamamos o método usando um ponto, como em qualquer linguagem OOP. Mas por baixo dos panos, o Go faz um truque esperto.



Value receiver vs Pointer receiver: batalha dos titãs



Em Go, existem dois tipos de receivers: por valor (value receiver) e por ponteiro (pointer receiver). A diferença é colossal, e não entender isso é uma causa frequente de bugs.



Value receiver

Quando você escreve func (u User) ..., o Go copia toda a struct. O método trabalha com uma cópia do objeto. Alterações dentro do método não afetarão o original.



func (u User) Birthday() {    u.Age++ // Isso alterará apenas a cópia!}

func main() { user := User{Name: "Bob", Age: 30} user.Birthday() fmt.Println(user.Age) // Ainda 30! Bug?}


Esse código não gerará erro de compilação, mas é logicamente incorreto. Você espera que a idade aumente, mas ela permanece a mesma. Bem-vindo ao mundo do value receiver!



Pointer receiver

Se você usar um ponteiro: func (u *User) ..., o método recebe uma referência ao objeto original. Agora, as alterações serão visíveis para todos.



func (u *User) Birthday() {    u.Age++ // Alteramos o original}

func main() { user := &User{Name: "Bob", Age: 30} // Criamos um ponteiro user.Birthday() fmt.Println(user.Age) // 31! Funciona!}


Regra de ouro: se o método altera o estado da struct ou a struct é grande (para evitar cópia), use pointer receiver. Se o método apenas lê dados, use value receiver.



Como isso funciona por baixo dos panos?



Agora, a parte mais interessante. Quando o compilador Go vê:

type Rectangle struct {    Width, Height float64}

func (r Rectangle) Area() float64 { return r.Width * r.Height}


Ele transforma isso em uma função comum, onde o receiver se torna o primeiro argumento:



                
                

Blogs

Book Recommendations