Pular para o conteúdo principal

victorstein.dev

68/100 Dias de Golang - Precisão quase infinita com math/big

# Precisão quase infinita com math/big

Vamos fazer um programa para calcular o fatorial de 1000.

package main

import "fmt"

func main() {
	var total uint64 = 1
	for i := 1; i < 1000; i++ {
		total = total * uint64(i)
	}
	fmt.Println(total)
}

Qual vai ser o resultado da operação?

➜  go run main.go
0

Zero! Isso mesmo! O que ocorre aqui é um problema de overflow, o valor de total excede o valor máximo que um uint64 pode armazenar (2**64 −1) e ocorre um estouro de memória. Em Go (e na maioria das linguagens de programação para tipos inteiros sem sinal), quando um overflow ocorre, o número “dá a volta” (wrap around). Ele começa a contar a partir de 0 novamente.

Ler Mais

67/100 Dias de Golang - Webscrapping com Colly

# Webscrapping com Colly

Colly é uma biblioteca de scraping para usar em golang. Com ela, conseguimos navegar por páginas HTML, capturar informações específicas, preencher formulários e até mesmo simular interações de usuário. Vamos fazer um script para pegar todos os dados do blog. Vamos iniciar um projeto e instalar a lib

go get -u github.com/gocolly/colly/v2

A arquitetura do colly é toda baseada em callbacks. Veja a documentação do Colly para saber mais. Sempre temos que inicial um collector c := colly.NewCollector() o Collector gerencia a comunicação de rede e é responsável pela execução dos callbacks associados enquanto o scraping está em execução.

Ler Mais

66/100 Dias de Golang - Jogo usando bubbletea e lipgloss - Parte 2

# Jogo usando bubbletea e lipgloss - Parte 2

Ontem criamos a base do jogo e estruturamos o projeto, hoje faremos a lógica usando o bubbletea e o lipgloss.

Vamos começar criando as estilizações dos textos. A documentação do lipgloss é muito legal e tem vários exemplos de como usar a biblioteca.

var (
	estiloJogador    = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("2"))
	estiloComputador = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("1"))
	estiloVencedor   = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("10"))
	estiloPlacar     = lipgloss.NewStyle().Foreground(lipgloss.Color("11"))
)

E depois passmos para a estrutura do bubbletea, seguindo o padrão Model, View e Update.

Ler Mais

65/100 Dias de Golang - Jogo usando bubbletea e lipgloss

# Jogo usando bubbletea e lipgloss

No post de hoje vamos fazer um jogo usando o bubbletea e o lipgloss. A ideia é só fazer um “baralho” e o jogador tira uma carta e o computador tira outra, quem tiver a carta mais alta vence. Em caso de empate no valor, o critério de desempate é a sequência de naipes.

Iniciamos o projeto:

go mod init jogo-cartas-tui

Instalação das libs:

Ler Mais

64/100 Dias de Golang - Iniciando uma TUI - Terminal User Interface

# Iniciando uma TUI - Terminal User Interface

Vamos verificar um lib muito legal do ecosistema, para a criação de Interfaces de usuário no terminal (TUIs), a Bubble Tea e aproveitar para ver a lib lipgloss. Vamos iniciar nosso projeto e instalar essas duas libs:

go get github.com/charmbracelet/bubbletea
go get github.com/charmbracelet/lipgloss

O Bubble Tea segue uma arquitetura bem definida:

  1. Model: Representa o estado da aplicação.
  2. Update: Lida com as atualizações de estado.
  3. View: Define como a interface é renderizada.

Esse código gera uma TUI, quando apertamos “i” um contador é incrementado, “d” decrementado e “q” a aplicação encerra.

Ler Mais

63/100 Dias de Golang - Gerando dados com Faker

# Gerando dados com Faker

Para não testarmos os dados sempre com o John Doe, temos a lib Faker ela permite gerar dados aleatórios para várias situações: nomes, endereços, números, textos e vários outros dados. Podemos usar isso em testes automatizados, mocks, geração de dados para popular um banco, …

Para instalar a lib:

go get -u github.com/go-faker/faker/v4

Vamos criar um script que define uma struct de User e vamos gerar dados fake para esse user. Veja que usamos o padrão das struct tags para definir as condições para o Faker

Ler Mais

62/100 Dias de Golang - Testes - Mockgen

# Testes - Mockgen

Vamos usar a lib gomock para gerar os mocks.

Vamos criar um projeto e instalar a lib:

go install go.uber.org/mock/mockgen@latest

Agora basta criar o nosso service/user_service.go.

package service

type UserService interface {
    GetUser(id int) (string, error)
    CreateUser(name string) error
}

E agora o comando mágico para gerar os mocks:

mockgen -source=./service/user_service.go -destination=./mocks/mock_user_service.go -package=mocks

Vai ser criado um arquivo mocks/mock_user_service.go

// Code generated by MockGen. DO NOT EDIT.
// Source: ./service/user_service.go
//
// Generated by this command:
//
//	mockgen -source=./service/user_service.go -destination=./mocks/mock_user_service.go -package=mocks
//

// Package mocks is a generated GoMock package.
package mocks

import (
	reflect "reflect"

	gomock "go.uber.org/mock/gomock"
)

// MockUserService is a mock of UserService interface.
type MockUserService struct {
	ctrl     *gomock.Controller
	recorder *MockUserServiceMockRecorder
	isgomock struct{}
}

// MockUserServiceMockRecorder is the mock recorder for MockUserService.
type MockUserServiceMockRecorder struct {
	mock *MockUserService
}

// NewMockUserService creates a new mock instance.
func NewMockUserService(ctrl *gomock.Controller) *MockUserService {
	mock := &MockUserService{ctrl: ctrl}
	mock.recorder = &MockUserServiceMockRecorder{mock}
	return mock
}

// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockUserService) EXPECT() *MockUserServiceMockRecorder {
	return m.recorder
}

// CreateUser mocks base method.
func (m *MockUserService) CreateUser(name string) error {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "CreateUser", name)
	ret0, _ := ret[0].(error)
	return ret0
}

// CreateUser indicates an expected call of CreateUser.
func (mr *MockUserServiceMockRecorder) CreateUser(name any) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUser", reflect.TypeOf((*MockUserService)(nil).CreateUser), name)
}

// GetUser mocks base method.
func (m *MockUserService) GetUser(id int) (string, error) {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "GetUser", id)
	ret0, _ := ret[0].(string)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetUser indicates an expected call of GetUser.
func (mr *MockUserServiceMockRecorder) GetUser(id any) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUser", reflect.TypeOf((*MockUserService)(nil).GetUser), id)
}

E depois basta escrever o teste para com o mock. Aqui a diferença vai ser a forma com que moldamos o comportamento do mock em relação ao testify. Veja a função mockUserService.EXPECT()

Ler Mais

61/100 Dias de Golang - Testes - Mocks

# Testes - Mocks

Já escrevi algumas vezes sobre testes aqui no blog:

Mas está faltando falar sobre Mocks. Mocks são estruturas que simulam o comportamento de componentes externos (como bancos de dados, APIs, …) para testar a lógica de negócio sem depender desses serviços. Em Go podemos fazer isso de diversas formas. Uma delas é utilizando a biblioteca testify.

Ler Mais

60/100 Dias de Golang - Jogo em UDP - Parte 6

# Jogo em UDP - Parte 6

Para fechar o jogo, vamos criar um objetivo. Qual player chegar primeiro na coordenada X, Y vence. O que vamos ter que alterar: fazer uma verificação se algum player está na posição de vitória, enviar uma mensagem de vitória depois que alguém alcançar a posição e travar a movimentação dos players após a vitória.

Vamos primeiro adicionar nossas variáveis:

var goalPosition = [2]int{arenaRows - 2, arenaCols - 2}
var gameOver = false
var winner string

Vamos adicionar uma verificação, caso gameOver seja verdade, não enviamos mais os comando para o canal

Ler Mais

59/100 Dias de Golang - Jogo em UDP - Parte 5

# Jogo em UDP - Parte 5

Hoje vamos corrigir um problema no jogo e mostrar o código completo. Como várias goroutines acessam a lista de players ou um player específico temos que usar um Mutex para não termos race condition. Vamos começar criando o mutex.

var players = make(map[string]*Player)
var playersMutex sync.Mutex

E sempre que acessarmos essa variável, temos que dar um Lock e Unlock nela. Vou colocar somente um exemplo aqui:

Ler Mais