Skip to content
Go

Go 1.27: Métodos Genéricos em Tipos Chegam para Transformar APIs e Bibliotecas

Published: Duration: 7:44
0:00 0:00

Transcript

Apresentadora: E aí, pessoal, bem-vindos de volta ao Allur! Eu sou a Juliana Santos e é um prazer ter vocês aqui com a gente em mais um episódio. Hoje, o papo é para quem, assim como eu, é fã de Go e estava esperando por aquele "salto" que faltava no sistema de tipos da linguagem. A gente sabe que o Go 1.18 trouxe os genéricos e mudou o jogo, né? Mas sempre ficou aquele gostinho de "quero mais", especialmente quando esbarrávamos na limitação de não poder criar métodos genéricos dentro de structs ou interfaces. Pois bem, o Go 1.27 chegou e, olha, ele não veio para brincadeira. O grande destaque dessa versão é justamente a introdução dos métodos genéricos em tipos, algo que promete transformar a forma como a gente desenha APIs e bibliotecas daqui para frente. Hoje, vamos entender o que muda na prática, como usar essa nova sintaxe e por que isso é o fim de muito código repetitivo que a gente odiava escrever. Para mergulhar nisso comigo, trouxe um convidado que manja muito do ecossistema Go. Apresentadora: Hoje eu recebo o Rafael Costa. O Rafa é Engenheiro de Software Sênior, especialista em sistemas distribuídos e um entusiasta de longa data da comunidade Go aqui no Brasil. Ele tem acompanhado de perto essa evolução dos genéricos desde os primeiros rascunhos lá atrás. Rafa, seja muito bem-vindo ao Allur! Convidado: Valeu, Juliana! É um prazer enorme estar aqui. O Allur é um podcast que eu acompanho sempre, então participar desse papo sobre o Go 1.27 é massa demais. E olha, você falou tudo: essa atualização é, tipo assim, o que a comunidade mais pedia desde que os genéricos "raiz" estrearam. Apresentadora: Pois é! E para a gente começar, Rafa, explica para o pessoal: por que essa versão 1.27 está sendo chamada de "um novo capítulo"? O que exatamente a gente não conseguia fazer antes que agora virou realidade com os métodos genéricos? Convidado: Cara, a real é que o Go 1.18 abriu a porteira, mas deixou uma cerca no meio do caminho. A gente conseguia fazer funções genéricas — tipo um `func Soma(a, b T)` — e estruturas genéricas. Mas, se você tivesse um struct, você não podia criar um método nele que tivesse o seu próprio parâmetro de tipo. Por exemplo, se você tivesse um container de dados e quisesse um método `.Transform()` que mudasse o tipo do dado interno, você tinha que apelar para funções externas ou para o bom e velho `interface{}` com aquele monte de type assertion que a gente sabe que é um perigo em runtime. No Go 1.27, essa trava caiu. Agora, o método pode ser genérico independentemente do struct ser ou não. É uma liberdade de design que a gente nunca teve no Go. Apresentadora: Nossa, total! Eu já perdi a conta de quantas vezes eu tive que criar funções utilitárias "soltas" só porque não conseguia colocar a lógica dentro do próprio objeto por causa dessa limitação. E sobre a sintaxe, Rafa? É muito diferente do que a gente já usa nas funções genéricas? Convidado: Pior que não, Juliana! A equipe do Go foi bem consistente. Se você já se acostumou com os colchetes dos genéricos, vai se sentir em casa. A diferença é que agora, na declaração do método, depois do receptor (aquele `(b *Bag)` ou `(mc MyContainer)`), você abre os colchetes e define o novo tipo pro método. Tipo assim: `func (b *Bag) Add(item T)`. É bem intuitivo. O compilador faz o trabalho pesado de inferir os tipos na maioria das vezes, então o uso no dia a dia fica muito fluido. Parece que o código "respira" melhor, sabe? Sem aquele boilerplate infinito. Apresentadora: "O código respira", gostei dessa expressão! (risos). Mas vem cá, na prática, onde você acha que o desenvolvedor vai sentir mais diferença? Você mencionou APIs e bibliotecas... tem algum caso de uso clássico que vai ficar muito mais elegante agora? Convidado: Com certeza! O exemplo de ouro são os Builders e as Fluent APIs. Imagina que você está construindo uma query de banco de dados. Antes, para você ter segurança de tipo no retorno, era uma ginástica danada. Agora, você pode ter um método `.Select()` direto no seu `QueryBuilder`. Você chama o método, passa o struct que representa sua tabela, e o builder já te devolve um resultado tipado como `T`. Sem precisar de cast, sem `interface{}`, tudo verificado em tempo de compilação. Outra coisa massa são as coleções. Sabe aquele método `Map` ou `Filter` que todo mundo queria ter em Slices ou Maps? Agora eles podem morar dentro do tipo da coleção de forma genérica. É um ganho de legibilidade absurdo. Apresentadora: Massa! Agora, mudando um pouco o tom... a gente sabe que no mundo da tecnologia "não existe almoço grátis". Colocar métodos genéricos assim não deixa o binário pesado ou a compilação lenta? Como o Go lida com isso por baixo dos panos? Convidado: Essa é a pergunta de um milhão de dólares, né? (risos). O Go usa uma mistura de técnicas, como a monomorfização — que é basicamente gerar uma versão do código para cada tipo que você usa — e dicionários de tipos. Sim, se você exagerar e criar métodos genéricos para tudo que é lado com centenas de combinações de tipos, o seu binário vai crescer e o tempo de compilação vai aumentar um pouco. Mas a equipe do Go é muito focada em performance. Nas versões recentes, eles otimizaram muito o linker e o compilador. Na maioria das aplicações reais, o impacto é mínimo perto do benefício de ter um código mais seguro e limpo. O segredo é: use com sabedoria, não precisa "genetificar" o sistema inteiro só porque agora pode. Apresentadora: Boa dica! E para quem está ouvindo a gente e já está pensando em rodar o `go get` e atualizar tudo... qual o melhor caminho para migrar? Vale a pena sair refatorando todo o código legado para usar métodos genéricos? Convidado: Olha, eu diria: calma lá! (risos). A minha sugestão é começar pelas "dores" mais óbvias. Sabe aquele código onde você tem cinco métodos quase iguais que só mudam o tipo do parâmetro? Ou aquele lugar onde o `interface{}` está te dando dor de cabeça com erros de tipo que só aparecem em produção? Começa por ali. Não precisa refatorar o que já funciona bem. O legal é ir adotando esses novos padrões em novos módulos ou bibliotecas internas. É um processo de aprendizado para o time também, para entender onde o genérico ajuda e onde ele complica a leitura. Apresentadora: Perfeito, Rafa. O equilíbrio é sempre o melhor caminho. Eu estou bem empolgada com essa versão, acho que o Go está ficando cada vez mais "maduro" sem perder aquela simplicidade que a gente ama, né? Convidado: Exatamente! O Go continua sendo Go. Ele não tentou virar um Java ou um C++ da vida. Ele trouxe os métodos genéricos de um jeito que faz sentido para o ecossistema. É mais poder na mão do dev, mas com aquela pegada pragmática de sempre. Apresentadora: Com certeza! Bom, chegamos ao fim do nosso papo. Rafael, valeu demais por ter vindo compartilhar esse conhecimento com a gente. Foi aula! Convidado: Valeu pelo convite, Juliana! Quem quiser trocar uma ideia sobre Go ou sobre essa versão 1.27, pode me achar no LinkedIn ou lá no GitHub. Vamos testar esses genéricos e bora codar! Apresentadora: É isso aí! As notas do episódio com os exemplos que o Rafa citou vão estar no nosso site. Recapitulando: o Go 1.27 com métodos genéricos em tipos é um marco que vai reduzir o boilerplate, deixar nossas APIs mais seguras e abrir portas para bibliotecas muito mais poderosas. Se você ainda não testou, a hora é agora! Valeu por sintonizar o Allur, eu sou Juliana Santos e a gente se vê no próximo episódio. Tchau!

Tags

Go Golang Coding software engineering backend generics type system