Entrevistas de Go focam em goroutines, channels, interfaces e tratamento de erros — a linguagem é pequena, então as perguntas vão fundo em vez de largo. Abaixo estão as mais comuns com respostas modelo.
Cada pergunta vem com uma resposta modelo para você comparar com a sua.
1
O que é uma goroutine e como ela se diferencia de uma thread do SO?
Resposta
Uma goroutine é uma função escalonada pelo runtime do Go em vez do sistema operacional. Ela começa com uma stack minúscula de poucos kilobytes que cresce sob demanda, enquanto uma thread do SO reserva megabytes, então um programa consegue sustentar centenas de milhares de goroutines. O runtime as multiplexa sobre um pool pequeno de threads do SO e troca em pontos de bloqueio sem um context switch do kernel.
2
Qual é a diferença entre um channel com buffer e um sem buffer?
Resposta
Um channel sem buffer é síncrono: o emissor bloqueia até que um receptor esteja pronto, então também funciona como ponto de sincronização. Um channel com buffer aceita até sua capacidade sem um receptor esperando e só bloqueia quando está cheio. Use sem buffer quando precisar de garantia de handoff, com buffer para suavizar picos — mas note que um buffer grande costuma esconder um problema de design em vez de resolvê-lo.
3
Como o select funciona? O que acontece se vários cases estiverem prontos?
Resposta
select espera sobre várias operações de channel e prossegue com a que estiver pronta. Se mais de uma estiver pronta, ele escolhe uniformemente ao acaso, o que evita a inanição de um único case. Uma cláusula default torna o statement inteiro não bloqueante, e um select sem nenhum case bloqueia para sempre — ocasionalmente usado deliberadamente para estacionar uma goroutine.
4
Explique a diferença entre um slice e um array. Como o append funciona?
Resposta
Um array tem um comprimento fixo que faz parte do seu tipo e é copiado por valor. Um slice é um header que guarda um ponteiro para um array subjacente, um comprimento e uma capacidade, então passá-lo copia só o header. O append escreve na capacidade sobrando quando há espaço; senão, aloca um array maior e copia, por isso o slice retornado pode não compartilhar mais memória com o original — e por isso você sempre deve atribuir o resultado.
5
O que é uma interface em Go? Por que elas são chamadas de implícitas?
Resposta
Uma interface é um conjunto de assinaturas de métodos; qualquer tipo que tenha esses métodos a satisfaz sem declarar isso. É isso que significa implícita — não existe palavra-chave implements, então você pode definir uma interface no pacote consumidor que tipos existentes já satisfazem. A orientação idiomática é manter as interfaces pequenas e defini-las onde são usadas, não junto à implementação.
6
Como você trata erros em Go? O que é error wrapping com %w?
Resposta
Erros são valores comuns retornados junto ao resultado e checados explicitamente em cada call site. Envolver com fmt.Errorf e o verbo %w preserva o erro original dentro de uma nova mensagem, então quem chama ainda consegue usar errors.Is para testar um valor sentinela ou errors.As para extrair um erro tipado. O wrapping adiciona contexto enquanto o erro viaja para cima, mantendo-o inspecionável programaticamente.
7
O que é context.Context e por que é necessário?
Resposta
Context carrega um sinal de cancelamento, um deadline e valores com escopo de request através das fronteiras da API. Quando um cliente desconecta ou um timeout dispara, cancelar o context se propaga para cada goroutine derivada dele, então consultas de banco de dados e chamadas HTTP abortam em vez de ficarem penduradas. A convenção é passá-lo como o primeiro parâmetro e nunca guardá-lo num struct.
8
O que é defer? Em que ordem as chamadas adiadas são executadas?
Resposta
defer agenda uma chamada para rodar quando a função ao redor retorna, não importa por qual caminho de retorno ou panic ela chegue lá. As chamadas adiadas rodam em ordem last-in-first-out, então o defer mais recente executa primeiro. Os argumentos são avaliados no momento em que o defer é escrito, não quando roda — uma fonte comum de surpresa ao adiar uma chamada que captura uma variável de loop.
9
Como você evita race conditions? Mutex ou channels?
Resposta
Uma data race é acesso concorrente não sincronizado onde pelo menos um lado escreve, e é detectável com a flag -race. Use sync.Mutex quando goroutines compartilham um pedaço de estado e você só precisa serializar o acesso a ele. Use channels quando você está transferindo a posse de dados entre goroutines — a máxima é compartilhar memória se comunicando, em vez de se comunicar compartilhando memória.
10
O que é uma interface nil e por que compará-la com nil pode te surpreender?
Resposta
Um valor de interface guarda duas palavras: um tipo e um valor. Ele é igual a nil só quando ambos são nil. Se você atribuir um ponteiro nil de um tipo concreto a uma interface, a palavra de tipo é definida, então a interface é não-nil mesmo que o ponteiro subjacente seja nil. Esse é o bug clássico onde uma função retorna um *MyError nil como error e a checagem err != nil de quem chama passa inesperadamente.