<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: ionnss</title>
    <description>The latest articles on Forem by ionnss (@ionnss).</description>
    <link>https://forem.com/ionnss</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F590424%2F326f424f-9f5f-40d6-828d-bcb0e903f638.png</url>
      <title>Forem: ionnss</title>
      <link>https://forem.com/ionnss</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ionnss"/>
    <language>en</language>
    <item>
      <title>Scrapper Concorrente</title>
      <dc:creator>ionnss</dc:creator>
      <pubDate>Tue, 05 Nov 2024 14:35:52 +0000</pubDate>
      <link>https://forem.com/ionnss/scrapper-concorrente-hl3</link>
      <guid>https://forem.com/ionnss/scrapper-concorrente-hl3</guid>
      <description>&lt;p&gt;&lt;a href="https://nodesource.com/products/nsolid" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwh5baqutb6746bql2nv.png" alt="N|Solid" width="162" height="32"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Objetivo do programa
&lt;/h2&gt;

&lt;p&gt;Acessar páginas web ao mesmo tempo para extrair o título de cada página e exibir esses títulos no terminal. Isso é feito utilizando concorrência em Go, que permite acessar várias páginas simultâneamente, economizando tempo. &lt;/p&gt;

&lt;h2&gt;
  
  
  Explicação do Código
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Pacotes utilizados
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import (
    "fmt"
    "net/http"
    "sync"
    "github.com/PuerkitoBio/goquery"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Função &lt;code&gt;fetchTitle&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Essa função é reponsável por:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Acessar uma página web (url)&lt;/li&gt;
&lt;li&gt;Extrair o título da página&lt;/li&gt;
&lt;li&gt;Evniar o resultado para um canal
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func fetchTitle(url string, wg *sync.WaitGroup, results chan&amp;lt;- string) {
    defer wg.Done() // Marca a goroutine como concluída no WaitGroup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parâmetros da função:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;url string&lt;/code&gt;: Representa o endereço da página web (url) que vamos acessar para obter o título&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wg *sync.WaitGroup&lt;/code&gt;: Pointeiro para um &lt;code&gt;WaitGroup, que usamos para sincornizar o término de todas as tarefas (goroutines) que estão rodando ao mesmo tempo. O&lt;/code&gt;*&lt;code&gt;indica que estamos passando um "enderço" para o&lt;/code&gt;WaitGroup` e não uma cópia dela.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;results chan&amp;lt;- string&lt;/code&gt;: Este é um canal unidirecional que permite enviar strings para outra parte do programa. Ele é usado para passar resultados (títulos ou mensagens de erro) para a função &lt;code&gt;main&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A linha &lt;code&gt;defer wg.Done()&lt;/code&gt; diz ao programa para marcar esta tarefa (goroutine) como concluída quando a função fetchTitle terminar. Isso é importante para que o &lt;code&gt;main&lt;/code&gt; saiba quando todas as tarefas foram concluídas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requisição HTTP
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
    req, err := http.Get(url)&lt;br&gt;
    if err != nil {&lt;br&gt;
        results &amp;lt;- fmt.Sprintf("Erro ao acessar %s: %v", url, err)&lt;br&gt;
        return&lt;br&gt;
    }&lt;br&gt;
    defer req.Body.Close()&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;http.Get(url)&lt;/code&gt;&lt;/strong&gt;: Esta linha faz um &lt;strong&gt;pedido HTTP GET&lt;/strong&gt; para a URL. Isso significa que estamos acessando a página e pedindo ao servidor o conteúdo dela.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;err != nil&lt;/code&gt;&lt;/strong&gt;: Aqui verificamos se houve algum erro ao acessar a página (por exemplo, se a página não existe ou o servidor não está respondendo). Se houver erro, enviamos uma mensagem para o canal &lt;code&gt;results&lt;/code&gt; e encerramos a função com &lt;code&gt;return&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;defer req.Body.Close()&lt;/code&gt;&lt;/strong&gt;: Isso garante que, depois que terminarmos de usar o conteúdo da página, liberaremos a memória alocada para armazená-lo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Verificação de Status
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
    if req.StatusCode != 200 {&lt;br&gt;
        results &amp;lt;- fmt.Sprintf("Erro ao acessar %s: status %d %s", url, req.StatusCode, req.Status)&lt;br&gt;
        return&lt;br&gt;
    }&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;req.StatusCode != 200&lt;/code&gt;&lt;/strong&gt;: Verificamos se o servidor respondeu com o código &lt;strong&gt;200 OK&lt;/strong&gt; (indica sucesso). Se não for 200, isso significa que a página não foi carregada corretamente. Então, enviamos uma mensagem de erro para o canal &lt;code&gt;results&lt;/code&gt; e encerramos a função.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Carregamento e Busca do Título
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
    doc, err := goquery.NewDocumentFromReader(req.Body)&lt;br&gt;
    if err != nil {&lt;br&gt;
        results &amp;lt;- fmt.Sprintf("Erro ao carregar documento de %s: %v", url, err)&lt;br&gt;
        return&lt;br&gt;
    }&lt;br&gt;
    title := doc.Find("title").Text()&lt;br&gt;
    results &amp;lt;- fmt.Sprintf("Título de %s: %s", url, title)&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;goquery.NewDocumentFromReader(req.Body)&lt;/code&gt;&lt;/strong&gt;: Carregamos o conteúdo HTML da página (fornecido por &lt;code&gt;req.Body&lt;/code&gt;) no &lt;code&gt;goquery&lt;/code&gt;, que permite navegar e buscar partes específicas do HTML.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;doc.Find("title").Text()&lt;/code&gt;&lt;/strong&gt;: Procuramos a tag &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; no HTML da página e pegamos o texto dentro dela (ou seja, o título).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;results &amp;lt;- fmt.Sprintf("Título de %s: %s", url, title)&lt;/code&gt;&lt;/strong&gt;: Enviamos o título extraído para o canal &lt;code&gt;results&lt;/code&gt;, onde ele será lido mais tarde.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Função &lt;code&gt;main&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;A função &lt;code&gt;main&lt;/code&gt; é a função principal que configura e controla o programa.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
func main() {&lt;br&gt;
    urls := []string{&lt;br&gt;
        "http://olos.novagne.com.br/Olos/login.aspx?logout=true",&lt;br&gt;
        "http://sistema.novagne.com.br/novagne/",&lt;br&gt;
    }&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;urls := []string{...}&lt;/code&gt;&lt;/strong&gt;: Definimos uma lista de URLs que queremos processar. Cada URL será passada para uma goroutine que extrairá o título da página.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuração do WaitGroup e do Canal
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
    var wg sync.WaitGroup&lt;br&gt;
    results := make(chan string, len(urls)) // Canal para armazenar os resultados&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;var wg sync.WaitGroup&lt;/code&gt;&lt;/strong&gt;: Criamos uma nova instância de &lt;code&gt;WaitGroup&lt;/code&gt;, que controlará o número de goroutines e garantirá que todas terminem antes que o programa finalize.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;results := make(chan string, len(urls))&lt;/code&gt;&lt;/strong&gt;: Criamos um canal &lt;code&gt;results&lt;/code&gt; com capacidade igual ao número de URLs. Esse canal armazenará as mensagens com os títulos ou erros.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Início das Goroutines
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
    for _, url := range urls {&lt;br&gt;
        wg.Add(1)&lt;br&gt;
        go fetchTitle(url, &amp;amp;wg, results)&lt;br&gt;
    }&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;for _, url := range urls&lt;/code&gt;&lt;/strong&gt;: Aqui, percorremos cada URL da lista.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;wg.Add(1)&lt;/code&gt;&lt;/strong&gt;: Para cada URL, incrementamos o contador do &lt;code&gt;WaitGroup&lt;/code&gt; para indicar que uma nova tarefa (goroutine) será iniciada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;go fetchTitle(url, &amp;amp;wg, results)&lt;/code&gt;&lt;/strong&gt;: Chamamos &lt;code&gt;fetchTitle&lt;/code&gt; como uma &lt;strong&gt;goroutine&lt;/strong&gt; para cada URL, ou seja, fazemos com que ela rode em paralelo com as outras.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Espera e Exibição dos Resultados
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
    wg.Wait()&lt;br&gt;
    close(results)&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;REPO: &lt;a href="https://github.com/ionnss/Scrapper-GoRoutine" rel="noopener noreferrer"&gt;https://github.com/ionnss/Scrapper-GoRoutine&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;ions,&lt;/p&gt;

&lt;p&gt;mais um dia da terra&lt;/p&gt;

</description>
      <category>go</category>
      <category>scrappe</category>
      <category>goroutines</category>
    </item>
    <item>
      <title>Organizador de arquivos em GO</title>
      <dc:creator>ionnss</dc:creator>
      <pubDate>Tue, 29 Oct 2024 15:31:39 +0000</pubDate>
      <link>https://forem.com/ionnss/organizador-de-seus-downloads-em-go-2hp6</link>
      <guid>https://forem.com/ionnss/organizador-de-seus-downloads-em-go-2hp6</guid>
      <description>&lt;p&gt;Olá, ions por aqui, novamente.&lt;/p&gt;

&lt;p&gt;O medo de estar aprendendo algo que um dia uma IA irá realizar, me deixa completamente angustiado. Mas, se "resolver problemas" ainda for uma exigência impostas aos seres humanos do futuro, por que não persistir?&lt;/p&gt;

&lt;p&gt;Desta vez trago outro tutorial. Menos inútil que o primeiro. Então vamos definir as estruturas dos "problemas", pois de uma coisa nós já sabemos: quem não tem problemas, é porque não procurou o suficiente. E quem ainda não os encontrou, é só uma questão de tempo para conseguir criá-los.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estrutura do projeto
&lt;/h2&gt;

&lt;p&gt;A estrutura mais simples do programa é:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Varrer uma pasta (por exemplo a pasta de downloads ou outro diretório)&lt;/li&gt;
&lt;li&gt;Identificar o tipo de cada arquivo no diretório em questão&lt;/li&gt;
&lt;li&gt;Mover o arquivo para uma subpasta correspondente ao seu tipo (imagens, videos, documentos...)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Iniciando o projeto
&lt;/h2&gt;

&lt;p&gt;Crie um diretório e navegue até ele:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir organizador
cd organizador
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Crie um arquivo organizador.go e inicie os módulos do mesmo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch organizador.go
go mod init organizador.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Você deve ter algo mais ou menos assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/organizador
.
├── go.mod
└── organizador.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Parte 1: Verificando se um diretório existe
&lt;/h2&gt;

&lt;p&gt;Vamos definir o diretório de &lt;code&gt;origemdirOrigem&lt;/code&gt; no qual realizaremos a organização. Com ele definido, vamos verificar se ele existe de fato, caso contrário, retornaremos um erro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "os"
)

// Defina o deretório o qual você quer organizar como variável global
var dirOrigem string := "/Users/User/Downloads" // Troque o diretório 

func main() {

    // Verificar se o diretório existe, caso contrário, retornar erro
    if _, err := os.Stat(dirOrigem); os.IsNotExist(err) {
        fmt.Println("BAD DIR :( \nDiretório não encontrado: ", dirOrigem)
        return
    } else {
        // Imprimir mensagem caso o diretório exista
        fmt.Println("GOOD DIR :) \nDiretório encontrado: ", dirOrigem)
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, vamo fazer algumas considerações a respeito do código acima:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A função &lt;code&gt;os.Stat&lt;/code&gt; retorna dois valores do tipo &lt;code&gt;os.FileInfo&lt;/code&gt; e erro &lt;code&gt;err&lt;/code&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;FileInfo&lt;/code&gt; é uma interface que retorna informações detalhadas de arquivos, que neste caso, não precisamos. Portanto, para ignorarmos essa interface, utilizamos &lt;code&gt;_,&lt;/code&gt;. Entretanto, não queremos ignorar o &lt;code&gt;erro: if _, err := ...&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Passamos o erro &lt;code&gt;err&lt;/code&gt; como parâmetro para a função &lt;code&gt;os.IsNotExist()&lt;/code&gt;, pois se o diretório não existir, a função &lt;code&gt;os.Stat()&lt;/code&gt; retornará um erro &lt;em&gt;NÃO NULO&lt;/em&gt;, fazendo com que a função  &lt;code&gt;os.IsNotExist()&lt;/code&gt; retorne &lt;code&gt;true&lt;/code&gt;, executando nossa mensagem: &lt;code&gt;BAD DIR :(&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Se &lt;code&gt;os.IsNotExist()&lt;/code&gt; retornar &lt;code&gt;false&lt;/code&gt;, teremos a impressão da mensagem da condição &lt;code&gt;else&lt;/code&gt;: &lt;code&gt;GOOD DIR :)&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Parte 2: Conceito de função de "callback" é uma doidera, bixo!
&lt;/h2&gt;

&lt;p&gt;Você reparou que aqui estamos indo aos poucos e nos deliciando com os bits e bytes ao som do teclado mecânico. _Tchaka tchaka bum! _  &lt;/p&gt;

&lt;p&gt;E agora nos vamos criar uma &lt;em&gt;&lt;strong&gt;função do tipo callback&lt;/strong&gt;&lt;/em&gt;. Algo que eu nunca tinha de fato aprendido sobre, ou nunca tive curiosidade o suficiente para questionar se um dia eu utilizei esse conceito em algum código python da minha vida pré-golang.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Função callback é uma função passada com argumento para outra função.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Se você já está familiarizado com o conceito, congrats, caso constrário, congrats. Ou seja, congrats!&lt;/p&gt;

&lt;p&gt;Agora vamos criar uma função callback &lt;code&gt;listarArquivos&lt;/code&gt; que será passada como argumento para outra função &lt;code&gt;filepath.Walk&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main() { 
// Restante do código
.
.
.

// Percorrer e listar os arquivos no diretório dirOrigem
    err := filepath.Walk(dirOrigem, listarArquivos)
    if err != nil {
        fmt.Println("Erro ao percorrer o diretório: ", err)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Função que lista os arquivos do diretório
func listarArquivos(caminho string, info os.FileInfo, err error) error {
    if err != nil {
        return err
    }

    // Ignorar diretórios e exibir apenas arquivos
    if !info.IsDir() &amp;amp;&amp;amp; !strings.HasPrefix(info.Name(), ".") {
        fmt.Println("Arquivo encontrado: ", info.Name())
    }
    return nil
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas calma, como que &lt;code&gt;filepath.Walk&lt;/code&gt; chama a Função de Callback?&lt;/p&gt;

&lt;p&gt;Quando você chama &lt;code&gt;filepath.Walk(dirOrigem, listarArquivos)&lt;/code&gt;, a função &lt;code&gt;filepath.Walk&lt;/code&gt; faz o trabalho pesado de percorrer todos os arquivos e subdiretórios dentro de &lt;code&gt;dirOrigem&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Para cada arquivo ou diretório encontrado, ela chama a função &lt;code&gt;listarArquivos&lt;/code&gt; com três argumentos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;caminho: o caminho completo para o arquivo ou diretório atual.&lt;/li&gt;
&lt;li&gt;info: um objeto &lt;code&gt;os.FileInfo&lt;/code&gt; que contém informações sobre o arquivo/diretório (como nome, se é um diretório, tamanho, etc.).&lt;/li&gt;
&lt;li&gt;err: um erro, caso algo dê errado ao acessar esse arquivo ou diretório.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O Go entende automaticamente que &lt;code&gt;listarArquivos&lt;/code&gt; deve receber esses três parâmetros porque &lt;code&gt;filepath.Walk&lt;/code&gt; espera uma função que siga exatamente essa assinatura:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Função Walk()
func Walk(root string, walkFn WalkFunc) error

// Tipo WalkFunc
type WalkFunc func(path string, info os.FileInfo, err error) error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repare que a função &lt;code&gt;Walk&lt;/code&gt; retorna um error! Isso é relevante! &lt;/p&gt;

&lt;p&gt;Por isso, que igualamos a nossa função &lt;code&gt;filepath.Walk(dirOrigem, listarArquivos)&lt;/code&gt; a um &lt;code&gt;err&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;err := filepath.Walk(dirOrgiem, listarArquivos)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pois no final das contas, por retornar um erro, ela é um erro XD&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo em Ação
&lt;/h3&gt;

&lt;p&gt;Aqui está uma visão mais detalhada do que acontece em cada passo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Percorrer e listar os arquivos no diretório
err := filepath.Walk(dirOrigem, listarArquivos)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para cada arquivo ou diretório em &lt;code&gt;dirOrigem&lt;/code&gt;, &lt;code&gt;filepath.Walk&lt;/code&gt; vai chamar &lt;code&gt;listarArquivos&lt;/code&gt; como se fosse algo assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;listarArquivos("/Users/User/Downloads/file1.txt", infoSobreFile1, nil)
listarArquivos("/Users/User/Downloads/file2.txt", infoSobreFile2, nil)
listarArquivos("/Users/User/Downloads/file3.mp3", infoSobreFile3, nil)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse exemplo, para cada chamada:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;caminho: recebe o caminho do arquivo ou diretório.&lt;/li&gt;
&lt;li&gt;info: contém informações sobre esse item (como o nome e o tipo).&lt;/li&gt;
&lt;li&gt;err: é usado para capturar qualquer erro específico ao acessar o arquivo/diretório.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Função de Callback
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;listarArquivos&lt;/code&gt; é uma função de callback que &lt;code&gt;filepath.Walk&lt;/code&gt; chama automaticamente com esses valores. Assim, não precisamos nos preocupar em definir os valores de &lt;code&gt;caminho&lt;/code&gt;, &lt;code&gt;info&lt;/code&gt; e &lt;code&gt;err&lt;/code&gt;; o &lt;code&gt;filepath.Walk&lt;/code&gt; já faz isso por nós.&lt;/p&gt;

&lt;p&gt;UFA! &lt;/p&gt;

&lt;p&gt;Agora faça aquele teste maroto em seu terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go run organizador.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Você pode ter com resultado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GOOD DIR :)
Diretório encontrado:  /Users/User/Downloads
Arquivo encontrado:  Suic_ SOS · 4.32pm · 10-25.jpeg
Arquivo encontrado:  Suic_ SOS.jpeg
Arquivo encontrado:  quantum-distortion-cyberpunk-music-234058.mp3
Arquivo encontrado:  slow-mode-enabled-cyberpunk-music-230623.mp3
Arquivo encontrado:  teaching-lp-20152-seminario-go.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ou:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go run organizador.go
BAD DIR :(
Diretório não encontrado:  /Users/User/Downloadss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse caso eu só coloquei um "s" extra em "Downloads" para que o &lt;code&gt;dirOrigem&lt;/code&gt; ficasse incorreto.&lt;/p&gt;

&lt;p&gt;Agora apague a função &lt;code&gt;listarArquivos&lt;/code&gt;, pois não vamos usá-la. &lt;/p&gt;

&lt;p&gt;Brincadeira, só vamos mudar ela de nome e adicionar outras lógicas.&lt;/p&gt;

&lt;h2&gt;
  
  
  PARTE 3: ORGANIZAR != ORGANIZADO
&lt;/h2&gt;

&lt;p&gt;Organizado é bom, organizar é fod@.&lt;/p&gt;

&lt;p&gt;Depois desta constatação genial da minha parte, vamos partir para a parte que nos interessa de fato: organizar a p*rr@ toda.&lt;/p&gt;

&lt;p&gt;Por ironia da vida, antes de organizar os arquivos, temos que organizar as idéias dos próximos passos. &lt;/p&gt;

&lt;p&gt;Nossa próxima função precisa, basicamente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Criar subpastas com base nas extensões de cada arquivo do nosso diretório dirOrigem, caso ela não exista. &lt;/li&gt;
&lt;li&gt;Mover os arquivos para suas respectivas pastas de acordo com suas extensões.&lt;/li&gt;
&lt;li&gt;Mas se os arquivos já estiverem nas subpastas organizadoras, ele não deve criá-las novamente.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vamos entender o que cada parte desse código faz:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Função que organiza os arquivos do diretório
func organizarArquivos(caminho string, info os.FileInfo, err error) error {
    if err != nil {
        return err
    }

    // Ignorar diretórios e exibir apenas arquivos
    if !info.IsDir() &amp;amp;&amp;amp; !strings.HasPrefix(info.Name(), ".") {
        fmt.Println("Arquivo encontrado: ", info.Name())

        // Obter extensões em letras minúsculas
        extensao := strings.ToLower(filepath.Ext(info.Name()))

        // Criar nome das subpastas diretamente em dirOrigem
        subpasta := filepath.Join(dirOrigem, extensao[1:])

        // Verificar se a subpasta já existe; caso contrário, criar a pasta
        if _, err := os.Stat(subpasta); os.IsNotExist(err) {
            err := os.Mkdir(subpasta, os.ModePerm)
            if err != nil {
                fmt.Println("Erro ao criar subpasta: ", err)
                return err
            }
        }

        // Caminho de destino para mover arquivos
        caminhoDestino := filepath.Join(subpasta, info.Name())

        // Verificar se o arquivo já está na subpasta
        if caminhoDestino == caminho {
            fmt.Printf("O arquivo %s já está na subpasta %s. Ignorando...\n", info.Name(), subpasta)
        } else {
            // Mover o arquivo para a subpasta
            err := os.Rename(caminho, caminhoDestino)
            if err != nil {
                fmt.Println("Erro ao mover arquivo: ", err)
                return err
            }
            fmt.Printf("Arquivo %s movido para %s\n", info.Name(), subpasta)
        }
    }
    return nil
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Estrutura da função organizarArquivos
&lt;/h3&gt;

&lt;p&gt;A função &lt;code&gt;organizarArquivos&lt;/code&gt; é chamada para cada arquivo ou pasta encontrada na estrutura de diretórios. Ela verifica as condições para organizar cada arquivo com base em sua extensão, criando subpastas e movendo arquivos, se necessário.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func organizarArquivos(caminho string, info os.FileInfo, err error) error {
    if err != nil {
        return err
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui, a função &lt;code&gt;organizarArquivos&lt;/code&gt; recebe três parâmetros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;caminho&lt;/code&gt;: o caminho completo para o arquivo ou diretório atual.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;info&lt;/code&gt;: informações do arquivo ou diretório, obtidas do tipo &lt;code&gt;os.FileInfo&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;err&lt;/code&gt;: um possível erro que pode ocorrer ao tentar acessar o item.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A primeira verificação é se existe algum erro ao acessar o arquivo/diretório. Caso positivo, ele é retornado imediatamente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Filtrando arquivos e ignorando diretórios ocultos
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if !info.IsDir() &amp;amp;&amp;amp; !strings.HasPrefix(info.Name(), ".") {
        fmt.Println("Arquivo encontrado: ", info.Name())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este trecho faz duas verificações:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;!info.IsDir()&lt;/code&gt;: verifica se o item não é um diretório (ou seja, é um arquivo).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;!strings.HasPrefix(info.Name(), ".")&lt;/code&gt;: verifica se o nome do arquivo não começa com ".", ignorando arquivos ocultos em sistemas baseados em Unix.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se as duas condições forem atendidas, o arquivo é exibido com &lt;code&gt;fmt.Println&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Identificando a extensão do arquivo e criando o nome da subpasta
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extensao := strings.ToLower(filepath.Ext(info.Name()))
subpasta := filepath.Join(dirOrigem, extensao[1:])

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;strings.ToLower(filepath.Ext(info.Name()))&lt;/code&gt;: extrai a extensão do arquivo (por exemplo, &lt;code&gt;.txt&lt;/code&gt;) e a transforma em minúsculas para garantir consistência.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;subpasta := filepath.Join(dirOrigem, extensao[1:])&lt;/code&gt;: cria o caminho completo da subpasta onde o arquivo será movido. O &lt;code&gt;extensao[1:]&lt;/code&gt; remove o ponto inicial (&lt;code&gt;.&lt;/code&gt;) da extensão, formando o nome da subpasta, como &lt;code&gt;txt&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Criando a subpasta, caso ainda não exista
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if _, err := os.Stat(subpasta); os.IsNotExist(err) {
            err := os.Mkdir(subpasta, os.ModePerm)
            if err != nil {
                fmt.Println("Erro ao criar subpasta: ", err)
                return err
            }
        }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui, a função:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verifica se a subpasta já existe usando &lt;code&gt;os.Stat&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Se a subpasta não existe (&lt;code&gt;os.IsNotExist(err)&lt;/code&gt;), ela é criada com &lt;code&gt;os.Mkdir(subpasta, os.ModePerm)&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;os.ModePerm&lt;/code&gt; define as permissões padrão para a nova pasta. Caso haja um erro ao criar a pasta, ele é exibido e retornado.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Definindo o caminho de destino do arquivo
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;caminhoDestino := filepath.Join(subpasta, info.Name())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste ponto, &lt;code&gt;caminhoDestino&lt;/code&gt; representa o caminho final para onde o arquivo será movido. Ele é construído usando &lt;code&gt;filepath.Join&lt;/code&gt;, para unir o caminho da subpasta ao nome do arquivo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verificando se o arquivo já está na pasta de destino
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if caminhoDestino == caminho {
            fmt.Printf("O arquivo %s já está na subpasta %s. Ignorando...\n", info.Name(), subpasta)
        } else {
            // Mover o arquivo para a subpasta
            err := os.Rename(caminho, caminhoDestino)
            if err != nil {
                fmt.Println("Erro ao mover arquivo: ", err)
                return err
            }
            fmt.Printf("Arquivo %s movido para %s\n", info.Name(), subpasta)
        }
    }
    return nil
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Este trecho compara o &lt;code&gt;caminhoDestino&lt;/code&gt; com o &lt;code&gt;caminho&lt;/code&gt; atual do arquivo. Se forem iguais, significa que o arquivo já está na subpasta correta, então ele é ignorado com uma mensagem (&lt;code&gt;fmt.Printf&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Caso contrário, &lt;code&gt;os.Rename(caminho, caminhoDestino)&lt;/code&gt; move o arquivo para a subpasta. Se houver erro durante a movimentação, ele é retornado.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Resumo Final
&lt;/h3&gt;

&lt;p&gt;A função:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Percorre um diretório, verificando cada item.&lt;/li&gt;
&lt;li&gt;Ignora diretórios e arquivos ocultos.&lt;/li&gt;
&lt;li&gt;Determina a extensão do arquivo e, com isso, a subpasta de destino.&lt;/li&gt;
&lt;li&gt;Cria a subpasta (se ainda não existir).&lt;/li&gt;
&lt;li&gt;Move o arquivo para a subpasta, a menos que ele já esteja lá.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O uso de &lt;code&gt;filepath.Walk(dirOrigem, organizarArquivos)&lt;/code&gt; passa essa função para cada arquivo dentro do diretório, fazendo com que todos sejam organizados automaticamente. &lt;/p&gt;

&lt;p&gt;Esse código se encaixa bem como uma função de organização de arquivos porque ele lida com a lógica de criação e movimentação em uma única função – uma forma eficiente e organizada de estrutura.&lt;/p&gt;

&lt;p&gt;REPO: &lt;a href="https://github.com/ionnss/organizador" rel="noopener noreferrer"&gt;https://github.com/ionnss/organizador&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;***Mais um dia na terra,&lt;br&gt;
ions&lt;/p&gt;

</description>
      <category>go</category>
      <category>tutorial</category>
      <category>programming</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Nietzsche reencarnado num gato, uma "ferramente" CLI feita com GO</title>
      <dc:creator>ionnss</dc:creator>
      <pubDate>Thu, 24 Oct 2024 18:28:03 +0000</pubDate>
      <link>https://forem.com/ionnss/nitzsche-reencarnado-num-gato-uma-ferramente-cli-3pb6</link>
      <guid>https://forem.com/ionnss/nitzsche-reencarnado-num-gato-uma-ferramente-cli-3pb6</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvkn5hb6671umymwquvcw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvkn5hb6671umymwquvcw.png" alt="Image description" width="476" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Estou com três projetos de GO em mente, mas com medo de terminá-los. Quero fazer e ter a sensação de que estou aprendendo no processo, ao invés de só copiar e colar códigos de stackoverflow e chatgpt.&lt;/p&gt;

&lt;p&gt;Eu quero dissecar os códigos, os conceitos e as ideias dos projetos para explicar em algum artigo, tipo esse. Acredito que assim eu conseguiria absorver bem o conhecimento por trás da produção dos códigos dos projetos.&lt;/p&gt;

&lt;p&gt;Dos três projetos, nenhum se mostra ser algo muito simples. Então pensei em construir um quarto projeto, mais simples, mais curto e que eu consiga aprender alguma coisa.&lt;/p&gt;

&lt;p&gt;Alguma coisa é melhor do que nada. E nada é melhor do que qualquer coisa inacabada.&lt;/p&gt;

&lt;p&gt;Mas enfim, vamos nessa!&lt;/p&gt;

&lt;h2&gt;
  
  
  FCAT?
&lt;/h2&gt;

&lt;p&gt;Ah, o nome é zuado mesmo, mas pensei no conceito de f-string, onde você introduz uma string em algum código.&lt;/p&gt;

&lt;p&gt;Quanto ao gato... bem, aí você me pegou. As pessoas gostam de gatos. Somado a isso pensei que Nietzsche seria um gato, ao invés de um cachorro, uma borboleta, um elefante, um dinossauro ou um bicho preguiça. Então é isso. É gato, porque SIM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qual é o problema?
&lt;/h2&gt;

&lt;p&gt;Começamos com o fato de já termos um arquivo txt com as citações do Nitzsche. O programa precisa selecionar alguma destas, de maneira aleatória e disponibilizar ao usuário. Além disso, precisa imprimir o gato em ASCII e formar um balão de diálogo em volta do quote exibido.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resumindo&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Arquivo com as citações&lt;/strong&gt;: arquivo .txt com citações do Nietzsche, onde cada citação esteja em uma linha separada.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Desenho de gato em ASCII&lt;/strong&gt;: Vamos definir o desenho do gato que será impresso no terminal.&lt;/p&gt;

&lt;p&gt;Gostei desse. Tem olhos hipnotizantes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; ,_     _
 |\\_,-~/
 / _  _ |    ,--.
(  @  @ )   / ,-'
 \  _T_/-._( (
 /         `. \
|         _  \ |
 \ \ ,  /      |
  || |-_\__   /
 ((_/`(____,-'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Carregar e selecionar uma citação aleatória&lt;/strong&gt;: O programa vai ler as citações de um arquivo .txt e selecionar uma aleatoriamente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Imprimir a citação com o balão de diálogo&lt;/strong&gt;: A citação será exibida dentro de um balão de diálogo acima do gato.&lt;/p&gt;

&lt;h2&gt;
  
  
  Letes go, bebê
&lt;/h2&gt;

&lt;p&gt;Antes de mais nada:&lt;/p&gt;

&lt;p&gt;Crie um diretório para o projeto e navegue até ele:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir fcat
cd fcat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Crie um arquivo main.go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inicialize os módulos do go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go mod init main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seu diretório deverá estar tipo assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fcat
.
├── go.mod
├── main.go
└── quotes.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora abra o main.go em sua IDE de preferência.&lt;/p&gt;

&lt;p&gt;NVIM se for do hype XD&lt;/p&gt;

&lt;h2&gt;
  
  
  Explicação do código:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Função &lt;code&gt;carregarCitations&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Essa função abre o arquivo de citações (nietzsche.txt), lê cada linha, e armazena todas as citações em uma lista.&lt;/p&gt;

&lt;p&gt;A função não irá receber argumentos, apenas retornará uma lista/slice de strings e erro: &lt;code&gt;string&lt;/code&gt; e &lt;code&gt;error&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "os"
    "bufio" 
)

func carregarCitations()([]string, error) {
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dentro da função iremos inicializar um slice/lista para receber todas as citações:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "os"
    "bufio" 
)

func carregarCitations() ([]string, error) {

    // Abrir uma lista para receber as citações
    var citas []string

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, vamos abrir o arquivo txt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "os"
    "bufio" 
)

func carregarCitations() ([]string, error) {

    // Abrir uma lista para receber as citações
    var citas []string

    // Abrir o arquivo txt com as citações
    arquivo, err := os.Open('quotes.txt')
    if err != nil {
        return nil, err // Retorna erro se falhar em abrir arquivo
    }
    defer arquivo.Close()   
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, nós vamos precisar criar um &lt;code&gt;"scanner"&lt;/code&gt; para realizar a leitura do nosso arquivo de citações &lt;code&gt;quotes.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ele também precisara ler cada linha do arquivo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "os"
    "bufio" 
)

func carregarCitations() ([]string, error) {

    // Abrir uma lista para receber as citações
    var citas []string

    // Abrir o arquivo txt com as citações
    arquivo, err := os.Open('quotes.txt')
    if err != nil {
        return nil, err // Retorna erro se falhar em abrir arquivo
    }
    defer arquivo.Close()   

    // Criar scanner para leitura do arquivo txt
    scanner := bufio.NewScanner(arquivo)


    // Ler cada linha de cada arquivo
    for scanner.Scan() {
        linha := scanner.Text() // Obter o texto da linha
        citas = append(citas, linha) // Realiza a adição das linhas à lista/slice citas
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, faremos a verificação do erro na leitura do arquivo txt de citações e o retorno da nossa lista com as citações que foram adicionadas à mesma.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "os"
    "bufio" 
)

func carregarCitations([]string, error) {

    // Abrir uma lista para receber as citações
    var citas []string

    // Abrir o arquivo txt com as citações
    arquivo, err := os.Open('quotes.txt')
    if err != nil {
        return nil, err // Retorna erro se falhar em abrir arquivo
    }
    defer arquivo.Close()   

    // Criar scanner para leitura do arquivo txt
    scanner := bufio.NewScanner(arquivo)

    // Ler cada linha de cada arquivo
    for scanner.Scan() {
        linha := scanner.Text() // Obter o texto da linha
        citas = append(citas, linha) // Realiza a adição das linhas à lista citas
    }

    // Verifica se houve erro na leitura do arq txt
    if err := scanner.Err(); err != nil {
        return nil, err
    }

    // Retornar nossa lista com citações
    return citas, nil // Retorna lista de citações
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora precisamos criar a função &lt;code&gt;main&lt;/code&gt; para retornar as citações e verificar se a função &lt;code&gt;carregarCitations&lt;/code&gt; está correta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main() {
    citations, err := carregarCitations()
    if err != nil {
        fmt.Println("Erro ao carregar citações", err)
        return
    }

    for _, citation := range citations {
        fmt.Println(citation)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O código deve estar assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "os"
    "bufio" 
)

func carregarCitations([]string, error) {

    // Abrir uma lista para receber as citações
    var citas []string

    // Abrir o arquivo txt com as citações
    arquivo, err := os.Open('quotes.txt')
    if err != nil {
        return nil, err // Retorna erro se falhar em abrir arquivo
    }
    defer arquivo.Close()   

    // Criar scanner para leitura do arquivo txt
    scanner := bufio.NewScanner(arquivo)

    // Ler cada linha de cada arquivo
    for scanner.Scan() {
        linha := scanner.Text() // Obter o texto da linha
        citas = append(citas, linha) // Realiza a adição das linhas à lista citas
    }

    // Verifica se houve erro na leitura do arq txt
    if err := scanner.Err(); err != nil {
        return nil, err
    }

    // Retornar nossa lista com citações
    return citas, nil // Retorna lista de citações
}

func main() {
    citations, err := carregarCitations()
    if err != nil {
        fmt.Println("Erro ao carregar citações", err)
        return
    }

    for _, citation := range citations {
        fmt.Println(citation)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora vamos executar o código no terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go run main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Você deve visualizar todas as citações do seu arquivo quotes.txt em seu terminal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Função &lt;code&gt;getRandomCitation&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Essa função usa a biblioteca &lt;code&gt;math/rand&lt;/code&gt; para selecionar uma citação aleatória da lista.&lt;/p&gt;

&lt;p&gt;Dentro dos parênteses da função &lt;code&gt;()&lt;/code&gt;, você define os parâmetros que a função recebe como entrada. No exemplo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;citations []string&lt;/code&gt; significa que a função &lt;code&gt;getRandomCitation&lt;/code&gt; espera um argumento chamado citations, que é um slice de strings (ou seja, uma lista de strings).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func getRandomCitation(citations []string

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;[]string&lt;/code&gt; é a sintaxe de Go para dizer "uma fatia de strings", ou seja, uma coleção ordenada de strings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quando você chama a função, você deve passar uma lista de citações (por exemplo, carregada do arquivo quotes.txt), e essa lista será usada dentro da função.&lt;/p&gt;

&lt;p&gt;Após os parênteses de entrada, logo antes do corpo da função {}, você especifica o tipo de valor que a função vai retornar.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;string&lt;/code&gt; logo após os parênteses significa que a função vai retornar uma string quando terminar de executar.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func getRandomCitation(citations []string) string {

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste caso, a função vai retornar uma citação aleatória, que é uma única string.&lt;/p&gt;

&lt;p&gt;Entretanto, precisamos gerar um valor aleatório, mas REALMENTE aleatório. Se utilizarmos somente &lt;code&gt;rand.Seed()&lt;/code&gt;, a semente padrão será sempre a mesma. Por isso precisamos passar como parâmetros, outras duas funções:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;time.Now(),&lt;/code&gt; que retorna o horário atual&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;UnixNano()&lt;/code&gt;, que converterá esse horário em um número inteiro, representando a quantidade de nanosegundos desde 1 de janeiro de 1970. A alta granularidade que é o pulo do gato XD&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E depois precisamos que a função retorne um índice aleatório de citations de acordo com o tamanho da lista de citações (length)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import (
    "math/rand" // Não esqueça de incluir essa biblioteca
    "time"      // Não esqueça de incluir essa biblioteca
)

func getRandomCitation(citations []string) string {

    // Inicializa um número aleatório
    rand.Seed(time.Now().UnixNano())

    // Seleciona um índice aleatório de citations
    randomIndex := rand.Intn(len(citations))

    // Retorna uma citação aleatória
    return cictaions[randomIndex]

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;len(citations)&lt;/code&gt; retorna o número de citações no slice.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;rand.Intn(n)&lt;/code&gt; gera um número aleatório entre 0 e n-1.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;rand.Intn(len(citations))&lt;/code&gt; seleciona um índice aleatório válido para acessar uma citação da lista.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E agora vamos alterar a função main, para imprimirmos a citação aleatória:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main() {
    // Chama função para carregar as citações 
    citations, err := carregarCitations()
    if err != nil {
        fmt.Println("Erro ao carregar citações:", err)
        return
    }

    // Obtém uma citação aleatória de citations utilizando a função getRandomCitation
    randomCitation := getRandomCitation(citations)

    // Imprime a citação aleatória
    fmt.Println("Citação aleatória", randomCitation)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O nosso código deve estar assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "bufio"
    "fmt"
    "os"
    "math/rand"
    "time"
)

// Função para carregar citações do arquivo quotes.txt
func carregarCitations() ([]string, error) {
    // Iniciar uma lista para receber todas as citações
    var citas []string

    // Abrir arquivo txt 
    arquivo, err := os.Open("quotes.txt")
    if err != nil {
        return nil, err // Retorna erro se falhar ao abrir o arquivo txt
    }
    defer arquivo.Close() // Garante o fechamento do arquivo ao final

    // Iniciar um scanner para leitura do arquivo
    scanner := bufio.NewScanner(arquivo)

    // Ler cada linha do arquivo txt
    for scanner.Scan() {
        linha := scanner.Text()
        citas = append(citas, linha)
    }

    // Verifica se houve algum erro durante a leitura do arquivo
    if err := scanner.Err(); err != nil {
        return nil, err
    }

    return citas, nil // Retorna lista de citações
}

func getRandomCitation(citations []string) string {
    // Inicializa o gerado de numero aleatório
    rand.Seed(time.Now().UnixNano())

    // Seleciona um índice aleatório
    randomIndex := rand.Intn(len(citations))

    // Retornar uma citação aleatório
    return citations[randomIndex]
}

func main() {
    // Chama a função para cerregar citações    
    citations, err := carregarCitations()
    if err != nil {
        fmt.Println("Erro ao carregar citações:", err)
        return
    }

    // Obtém uma citação aleatória de citations utilizando a função getRandomCitation
    randomCitation := getRandomCitation(citations)

    // Imprime a citação aleatória
    fmt.Println("Citação aleatória:", randomCitation)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora rode o &lt;code&gt;main.go&lt;/code&gt; em seu terminal a fim de verificar se conseguimos uma citação aleatória:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go rum main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Função &lt;code&gt;imprimirGato&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Essa função exibe o desenho de um gato em ASCII e imprime a citação dentro de um balão de diálogo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func imprimirGato(citacao string) {
    tamanhoBalao := len(citacao)
    linhaTopo := " " + strings.Repeat("-", tamanhoBalao+2)
    linhaCima := "/" + strings.Repeat(" ", tamanhoBalao+2) + "\\"
    linhaCitacao := fmt.Sprintf("| %s |", citacao)
    linhaBaixo := "\\" + strings.Repeat(" ", tamanhoBalao+2) + "/"
    linhaBase := " " + strings.Repeat("-", tamanhoBalao+2)

    // Imprime o balão de diálogo
    fmt.Println(linhaTopo)
    fmt.Println(linhaCima)
    fmt.Println(linhaCitacao)
    fmt.Println(linhaBaixo)
    fmt.Println(linhaBase)

    // Imprime o desenho do gato em ASCII com barras escapadas corretamente
    fmt.Println(`        \   
             \  
               ,_     _
               |\\_,-~/
               / _  _ |    ,--.
              (  @  @ )   / ,-'
               \  _T_/-._( (
               /         \. \
              |         _  \ |
               \ \ ,  /      |
                || |-_\__   /
               ((_/` + "`(____,-'`)")
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Função &lt;code&gt;main&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Na função &lt;code&gt;main()&lt;/code&gt;, o programa carrega as citações, seleciona uma aleatória e imprime o gato com a citação em um balão.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main() {
    // Carregar as citações do arquivo
    citations, err := carregarCitations()
    if err != nil {
        fmt.Println("Erro ao carregar citações:", err)
        return
    }

    // Obter uma citação aleatória
    randomCitation := getRandomCitation(citations)

    // Imprimir o balão com o gato e a citação aleatória
    imprimirGato(randomCitation)
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nosso código final deve estar assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "bufio"
    "fmt"
    "math/rand"
    "os"
    "strings"
    "time"
)

// Função para carregar citações do arquivo quotes.txt
func carregarCitations() ([]string, error) {
    var citas []string

    arquivo, err := os.Open("quotes.txt")
    if err != nil {
        return nil, err
    }
    defer arquivo.Close()

    scanner := bufio.NewScanner(arquivo)
    for scanner.Scan() {
        linha := scanner.Text()
        citas = append(citas, linha)
    }

    if err := scanner.Err(); err != nil {
        return nil, err
    }

    return citas, nil
}

func getRandomCitation(citations []string) string {
    rand.Seed(time.Now().UnixNano())
    randomIndex := rand.Intn(len(citations))
    return citations[randomIndex]
}

func imprimirGato(citacao string) {
    tamanhoBalao := len(citacao)
    linhaTopo := " " + strings.Repeat("-", tamanhoBalao+2)
    linhaCima := "/" + strings.Repeat(" ", tamanhoBalao+2) + "\\"
    linhaCitacao := fmt.Sprintf("| %s |", citacao)
    linhaBaixo := "\\" + strings.Repeat(" ", tamanhoBalao+2) + "/"
    linhaBase := " " + strings.Repeat("-", tamanhoBalao+2)

    // Imprime o balão de diálogo
    fmt.Println(linhaTopo)
    fmt.Println(linhaCima)
    fmt.Println(linhaCitacao)
    fmt.Println(linhaBaixo)
    fmt.Println(linhaBase)

    // Imprime o desenho do gato em ASCII com barras escapadas corretamente
    fmt.Println(`        \   
             \  
               ,_     _
               |\\_,-~/
               / _  _ |    ,--.
              (  @  @ )   / ,-'
               \  _T_/-._( (
               /         \. \
              |         _  \ |
               \ \ ,  /      |
                || |-_\__   /
               ((_/` + "`(____,-'`)")
}

func main() {
    citations, err := carregarCitations()
    if err != nil {
        fmt.Println("Erro ao carregar citações:", err)
        return
    }

    randomCitation := getRandomCitation(citations)
    imprimirGato(randomCitation)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Finalizando
&lt;/h2&gt;

&lt;p&gt;Agora nos resta compilar nosso programa e executar.&lt;/p&gt;

&lt;p&gt;Compile seu arquivo main.go como fcat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go build -o fcat main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E por fim, execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./fcat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O resultado foi esse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; ------------------------------------------------------
/                                                      \
| He who has a why to live for can bear almost any how |
\                                                      /
 ------------------------------------------------------
        \
             \
               ,_     _
               |\\_,-~/
               / _  _ |    ,--.
              (  @  @ )   / ,-'
               \  _T_/-._( (
               /         \. \
              |         _  \ |
               \ \ ,  /      |
                || |-_\__   /
               ((_/`(____,-'`)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Achei interessante como algo tão simples pode se tornar tão complicado de executar.&lt;/p&gt;

&lt;p&gt;Mas o que me impressionou foi a frase de saída do programa: "He who has a why to live for can bear almost any how"&lt;/p&gt;

&lt;p&gt;Que a frase acima lhe inspire a continuar aprendendo.&lt;/p&gt;

&lt;p&gt;REPO: &lt;a href="https://github.com/ionnss/fcat" rel="noopener noreferrer"&gt;https://github.com/ionnss/fcat&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;ions,&lt;/p&gt;

&lt;p&gt;Mais um dia na terra&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>go</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
