Pular para o conteúdo principal

victorstein.dev

23/100 Dias de Golang - Manipulação de arquivos

# Manipulação de arquivos

Clássico conteúdo de manipulação de arquivos, como fazer a leitura, como escrever, como escreve com append, como ler linha a linha, como renomear um arquivo, como deletar… O famoso CRUD dos arquivos.

# Criar e escrever

Para criar um arquivo, vamos usar a função os.Create(nomeArquivo) da biblioteca padrão os.

nomeArquivo := "meu_arquivo.txt"

arquivo, err := os.Create(nomeArquivo)
if err != nil {
	panic(err)
}

Lembrar de sempre quando trabalhar com arquivos usar o defer. O defer atrasa a execução da função que o segue até que a função em que ele está seja concluída. No caso de arquivo.Close(), isso garante que o arquivo será fechado corretamente, independentemente de como a função termina. O mais legal é que isso é independente de como a função finaliza, seja com com um erro o de forma normal.

Ler Mais

22/100 Dias de Golang - Biblioteca “time”

# Biblioteca “time”

Já usamos em vários exemplos essa biblioteca, usando para o famose sleep. Agora vamos dar uma olhada mais a fundo nela. Já vamos começar com a mais clásica de todas, pegar o horário atual

package main

import (
	"fmt"
	"time"
)

func main() {

	now := time.Now()

	fmt.Println(now)
}

Se você executar esse programa, verá uma saída nesse format:

2025-04-03 21:31:41.020649931 -0300 -03 m=+0.000047023

Perceba que o timezone vem no fomato -0300 e no formato abreviado -03. O diferente é o retorno do m=+0.000047023. Esse campo aparece quando imprimimos diretamente um time.Time. Esse valor é conhecido como “monotonic clock reading”, ou tempo monotônico, e serve para ajudar o Go a fazer medições de tempo com alta precisão. m=+0.000058133 quer dizer que o Go registrou esse momento como sendo +58.133 microssegundos desde um ponto de referência interno. Ele serve para medir duração entre eventos, como timers, benchmarks, e medições de performance.

Ler Mais

21/100 Dias de Golang - JSON

# JSON

Vamos sair um pouco do assunto das goroutines e ir para uma coisa mais “tranquila”, vamos falar sobre JSON, especificamente no Golang. Vamos dar um exemplo inicial de como transformar uma struct em um JSON. Depois de 20 dias, estou mais acostumado com a sintaxe do Go, espero que você também esteja.

package main

import "encoding/json"

type Animal struct {
	NomeCientifico  string
	NomePopular     string
	Patas           int
	NaturalDoBrasil bool
}

func main() {

	caramelo := Animal{
		NomeCientifico:  "Caramelus Brasiliensis",
		NomePopular:     "Caramelo",
		Patas:           4,
		NaturalDoBrasil: true,
	}

	res, err := json.Marshal(caramelo)

	if err != nil {
		println(err)
	}

	println(res)

}

A parte nova desse programa é a parte da serialização da struc para JSON. Fazemos isso com a função res, err := json.Marshal(caramelo). A função json.Marshal retorna um ([]byte, error). Perceba que é retornado um slice de bytes, rodando esse programa temos a seguinte saída:

Ler Mais

20/100 Dias de Golang - Exemplo de goroutines, mutex e channels

# Resolvendo o problema do Starbucks

Vamos “resolver” o problema do Starbucks. Para quem não sabe do que estou falando: Problema de race condition no starbucks afeta gift cards. Vamos criar um programa bem simples para simular isso e já aproveitamos para treinar os conhecimentos até aqui. Então o que teremos: pessoas com saldo nas contas e uma função que você pode transferir saldo do gift card de uma conta para outra. Vou fazer o programa de forma evolucional, começando bem simples e incrementar aos poucos.

Ler Mais

19/100 Dias de Golang - Channels

# Channels

Os channels nos permitem segurança para comunicação entre as threads. Extraído do livro A Linguagem de Programação Go:

Um canal é um sistema de comunicação que permite a uma gorrotina enviar valores para outra gorrotina E como tudo é fortemente tipado no Go, cada canal possui um tipo, veja como é simples criar um channel:

ch := make(chan int)

Com canais podemos fazer duas operações, enviar e receber. Vamos fazer um exemplo bem simples. Criar uma goroutine que envia uma informação para um canal e vamos printar esse valor fora dessa goroutine

Ler Mais

18/100 Dias de Golang - Goroutines, WaitGroup, Race condition e Mutex

# Goroutines

Vamos continuar a nossa jornada com as goroutines. Quero fazer mais um exemplo aqui.

package main

import (
	"fmt"
	"time"
)

func task(name string, n int) {

	for i := 0; i < n; i++ {
		fmt.Printf("Task: %s, i:%d/%d\n", name, i, n)
		time.Sleep(500 * time.Millisecond)

	}
}

func main() {

	go task("1", 5)
	go task("2", 7)

	time.Sleep(10 * time.Second)

}

Veja a saída desse programa:

Task: 2, i:0/7
Task: 1, i:0/5
Task: 1, i:1/5
Task: 2, i:1/7
Task: 2, i:2/7
Task: 1, i:2/5
Task: 1, i:3/5
Task: 2, i:3/7
Task: 2, i:4/7
Task: 1, i:4/5
Task: 2, i:5/7
Task: 2, i:6/7

Talvez esse exemplo seja mais elucidativo do que o anterior. Nele podemos ver claramente as duas goroutines rodando. O mais legal disso tudo foi a simplicidade de criar uma goroutine. No python, por exemplo, você teria que usar o threading ou multiprocessing para fazer isso. Perceba que o time.Sleep(10 * time.Second) é só um recursso técnico não convencional gambiarra. Uma das formas de resolver isso é um WaitGroup.

Ler Mais

17/100 Dias de Golang - Concorrência e Goroutines

# Concorrência

A concorrência é um dos pilares do desenvolvimento moderno, permitindo que programas executem múltiplas tarefas simultaneamente para melhor aproveitamento dos recursos computacionais. Em sistemas tradicionais, a concorrência é frequentemente implementada usando threads gerenciadas pelo sistema operacional, o que pode introduzir sobrecarga significativa devido à necessidade de alternância de contexto (context switching) e sincronização complexa.

Go foi projetado com a concorrência em mente, oferecendo uma abordagem mais eficiente e acessível por meio das goroutines. Essas unidades leves de execução permitem a construção de programas altamente concorrentes sem os custos elevados das threads convencionais. O runtime do Go gerencia automaticamente o escalonamento das goroutines, otimizando o uso do processador e simplificando o desenvolvimento de aplicações escaláveis e performáticas.

Ler Mais

16/100 Dias de Golang - Requests para APIs Externas - Parte 3

# Requests para APIs Externas - Parte 3

Go possui um forte compromisso com a biblioteca padrão. Isso significa que a maioria das funcionalidades que você precisa já estão disponíveis na biblioteca padrão. Porém, em alguns casos, você pode precisar de uma biblioteca externa. Vamos implantar o mesmo código usando a biblioteca [github.com/go-resty/resty/v3](https://github.com/go-resty/resty), que é uma biblioteca de cliente HTTP muito popular e fácil de usar.

package main

import (
	"fmt"
	"net/http"

	"github.com/go-resty/resty/v2"
)

func main() {
	client := resty.New()

	// Faz a requisição GET
	resp, err := client.R().
		Get("https://the-one-api.dev/v2/book")
	if err != nil {
		fmt.Println("Erro ao fazer request:", err)
		return
	}
	defer resp.RawResponse.Body.Close()

	// Verifica o status da resposta
	if resp.StatusCode() != http.StatusOK {
		fmt.Println("Erro na resposta:", resp.Status())
		return
	}

	// Imprime o corpo da resposta
	fmt.Println("Resposta:", string(resp.Body()))
}

A biblioteca resty facilita a criação de requisições HTTP. No exemplo acima, usamos o método R() para criar uma nova requisição e o método Get() para fazer a requisição GET. A resposta é retornada como um objeto Response, que possui métodos para acessar o corpo da resposta, o status da resposta e outros detalhes. Vou adicionar um exemplo adicionar um bearer token no cabeçalho da requisição. A única coisa que temos que fazer é adicionar o método SetAuthToken na requisição.

Ler Mais

15/100 Dias de Golang - Requests para APIs Externas - Parte 2

# Requests para APIs Externas - Parte 2

Agora que já sabemos como fazer um request básico, vamos incrementar um pouco. Adiciar a API Key, fazer um request para uma rota que precisa de autenticação. Vamos fazer um request para a rota /movie da API do Senhor dos Anéis, que precisa de autenticação. Para isso, precisamos passar a chave de API no cabeçalho da requisição.

package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://the-one-api.dev/v2/movie"

	// Cria a request manualmente
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		fmt.Println("Erro ao criar request:", err)
		return
	}

	// Adiciona o header Authorization
	req.Header.Add("Authorization", "Bearer your-api-key-123")

	// Faz a requisição usando o client padrão
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Println("Erro ao fazer request:", err)
		return
	}
	defer resp.Body.Close()

	// Lê a resposta
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Erro ao ler resposta:", err)
		return
	}


	fmt.Println("Resposta:", string(body))
}

A diferença nesse código é que criamos a requisição manualmente com o método http.NewRequest, onde passamos o método HTTP, a URL e o corpo da requisição (que no caso é nil). Depois, adicionamos o cabeçalho de autenticação com o método Header.Add. Por fim, fazemos a requisição com o método http.DefaultClient.Do, que retorna a resposta. Nesse caso o request vai falhar, pois não temos a chave de API. O último print vai imprimir o erro da requisição.

Ler Mais

14/100 Dias de Golang - Requests para APIs Externas - Parte 1

# Requests para APIs Externas - Parte 1

Vou tentar fazer alguma coisa mais prática, nesses últimos dias, foquei no estudo da base da linguagem, entender sintaxe, como as coisas funcionam, mas agora quero fazer algo mais prático. Vamos fazer uma aplicação que consome uma API externa, para isso, vamos usar a API do Senhor dos Anéis, que é uma API gratuita e fácil de usar. Para usar alguns endpoints, precisamos de uma chave de API, mas alguns endpoints não precisam. Para conseguir a chave, basta se cadastrar no site e gerar uma chave.

Ler Mais