Biblioteca lo para Go: Utilitárias Genéricas (Lodash para Go)
No mundo do desenvolvimento em Go, surge frequentemente a necessidade de funções práticas para trabalhar com coleções, como as existentes em outras linguagens (por exemplo, map, filter, reduce do JavaScript ou Python). A biblioteca padrão do Go oferece um conjunto mínimo de ferramentas, e escrever loops for repetitivos para cada operação se torna cansativo. É aqui que a biblioteca lo entra em cena — um poderoso conjunto de utilitárias genéricas, inspirado na popular biblioteca JavaScript Lodash.
A biblioteca lo utiliza genéricos (tipos genéricos), introduzidos no Go 1.18+, para fornecer funções type-safe para trabalhar com slices, maps, channels e outras estruturas de dados. Em vez de escrever for i := range slice { ... } para cada transformação, você pode usar uma única linha de código: lo.Map(slice, transformFunc). Isso torna o código mais legível, conciso e menos propenso a erros.
Por que usar lo? Primeiro, economia de tempo: você para de escrever código boilerplate. Segundo, aumento da confiabilidade: as funções da biblioteca são cuidadosamente testadas e cobrem diversos casos extremos. Terceiro, padronização: toda a equipe usa as mesmas funções com nomes claros, facilitando as revisões de código. lo é um must-have para qualquer projeto Go que lide ativamente com coleções de dados.
Instalação
A instalação da biblioteca lo é feita da forma padrão do Go, através do go get. Certifique-se de ter a versão Go 1.18 ou superior instalada (já que a biblioteca usa genéricos).
go get github.com/samber/lo@latest
Após executar este comando, a biblioteca será adicionada ao seu arquivo go.mod. Agora você pode importá-la no seu código:
import "github.com/samber/lo"
Início Rápido
Vamos escrever um programa simples que usa lo para filtrar e transformar um slice de números.
package main
import (
"fmt"
"github.com/samber/lo"
)
func main() {
// Slice original de números
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// Filtra apenas os números pares
evenNumbers := lo.Filter(numbers, func(x int, _ int) bool {
return x%2 == 0
})
fmt.Println("Números pares:", evenNumbers) // [2 4 6 8 10]
// Dobra cada número
doubled := lo.Map(evenNumbers, func(x int, _ int) int {
return x * 2
})
fmt.Println("Pares dobrados:", doubled) // [4 8 12 16 20]
// Soma todos os números
sum := lo.Sum(doubled)
fmt.Println("Soma:", sum) // 60
}
Como você pode ver, o código ficou muito mais declarativo e legível. Evitamos escrever três loops for separados.
Principais Métodos e Funções
Abaixo está uma lista das funções-chave da biblioteca lo com exemplos de uso. A maioria das funções recebe um slice e uma função de callback.
1. lo.Filter
Assinatura: func Filter[T any](collection []T, predicate func(item T, index int) bool) []T
O que faz: Cria um novo slice contendo apenas os elementos do slice original para os quais a função predicado retornou true.
package main
import (
"fmt"
"github.com/samber/lo"
)
func main() {
names := []string{"Alice", "Bob", "Charlie", "David", "Eve"}
// Mantém apenas nomes com mais de 3 caracteres
longNames := lo.Filter(names, func(name string, _ int) bool {
return len(name) > 3
})
fmt.Println(longNames) // [Alice Charlie David]
}
2. lo.Map
Assinatura: func Map[T any, R any](collection []T, iteratee func(item T, index int) R) []R
O que faz: Transforma cada elemento de um slice usando uma função de iteração e retorna um novo slice com os resultados.
package main
import (
"fmt"
"github.com/samber/lo"
)
func main() {
numbers := []int{1, 2, 3, 4, 5}
// Converte cada número para sua representação em string
stringNumbers := lo.Map(numbers, func(x int, _ int) string {
return fmt.Sprintf("Número: %d", x)
})
fmt.Println(stringNumbers) // [Número: 1 Número: 2 Número: 3 Número: 4 Número: 5]
}
3. lo.Reduce
Assinatura: func Reduce[T any, R any](collection []T, accumulator func(agg R, item T, index int) R, initial R) R
O que faz: Reduz um slice a um único valor acumulado, aplicando uma função acumuladora a cada elemento.
package main
import (
"fmt"
"github.com/samber/lo"
)
func main() {
numbers := []int{1, 2, 3, 4, 5}
// Calcula o produto de todos os números
product := lo.Reduce(numbers, func(agg int, item int, _ int) int {
return agg * item
}, 1)
fmt.Println("Produto:", product) // 120
}
4. lo.Find
Assinatura: func Find[T any](collection []T, predicate func(item T) bool) (T, bool)
O que faz: Encontra o primeiro elemento em um slice que satisfaz a condição do predicado. Retorna o elemento e um booleano indicando se foi encontrado.
package main
import (
"fmt"
"github.com/samber/lo"
)
func main() {
numbers := []int{10, 20, 30, 40, 50}
// Encontra o primeiro número maior que 25
found, ok := lo.Find(numbers, func(x int) bool {
return x > 25
})
if ok {
fmt.Println("Encontrado:", found) // 30
} else {
fmt.Println("Número não encontrado")
}
}
5. lo.Uniq
Assinatura: func Uniq[T comparable](collection []T) []T
O que faz: Remove elementos duplicados de um slice, mantendo a ordem original.
package main
import (
"fmt"
"github.com/samber/lo"
)
func main() {
numbers := []int{1, 2, 2, 3, 3, 3, 4, 5, 5}
unique := lo.Uniq(numbers)
fmt.Println("Únicos:", unique) // [1 2 3 4 5]
}
6. lo.Chunk
Assinatura: func Chunk[T any](collection []T, size int) [][]T
O que faz: Divide um slice em pedaços (chunks) de tamanho especificado.
package main
import (
"fmt"
"github.com/samber/lo"
)
func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7}
chunks := lo.Chunk(numbers, 3)
fmt.Println("Pedaços:", chunks) // [[1 2 3] [4 5 6] [7]]
}
7. lo.Flatten
Assinatura: func Flatten[T any](collection [][]T) []T
O que faz: Achata um slice de slices em um único slice.
package main
import (
"fmt"
"github.com/samber/lo"
)
func main() {
nested := [][]int{{1, 2}, {3, 4, 5}, {6}}
flat := lo.Flatten(nested)
fmt.Println("Achatado:", flat) // [1 2 3 4 5 6]
}
8. lo.Sum
Assinatura: func Sum[T constraints.Integer | constraints.Float](collection []T) T
O que faz: Calcula a soma de todos os elementos numéricos em um slice.
package main
import (
"fmt"
"github.com/samber/lo"
)
func main() {
numbers := []float64{1.5, 2.5, 3.0}
total := lo.Sum(numbers)
fmt.Println("Soma total:", total) // 7.0
}
Conclusão
A biblioteca lo é uma ferramenta indispensável para qualquer desenvolvedor Go que queira escrever código mais limpo, eficiente e expressivo. Com suas funções utilitárias genéricas, você pode substituir dezenas de loops manuais por chamadas de função concisas e legíveis. Seja para filtrar, mapear, reduzir ou manipular coleções de dados, lo oferece uma solução elegante e testada.
Comece a usar lo hoje mesmo e veja como seu código Go pode se tornar mais produtivo e agradável de escrever!
Também na biblioteca
Parsing de HTML em C# (.NET): bibliotecas HtmlAgilityPack e AngleSharp
Apache Camel para Java: guia completo com exemplos práticos
MetricsKit — monitoramento de aplicativos Swift (iOS/macOS)