<?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>DEV Community: Igor Melo</title>
    <description>The latest articles on DEV Community by Igor Melo (@igormelo).</description>
    <link>https://dev.to/igormelo</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%2F707437%2F0218fb91-daf0-4318-841f-5830db01481f.png</url>
      <title>DEV Community: Igor Melo</title>
      <link>https://dev.to/igormelo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/igormelo"/>
    <language>en</language>
    <item>
      <title>Go 1.22 e o novo router HTTP</title>
      <dc:creator>Igor Melo</dc:creator>
      <pubDate>Wed, 07 Feb 2024 00:50:47 +0000</pubDate>
      <link>https://dev.to/igormelo/go-122-e-o-novo-router-http-1npo</link>
      <guid>https://dev.to/igormelo/go-122-e-o-novo-router-http-1npo</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;O &lt;code&gt;http.ServeMux&lt;/code&gt; do Go ganhou novas features muito aguardadas pelos desenvolvedores, e como sempre, essas features são retrocompatíveis.&lt;/p&gt;

&lt;p&gt;Em resumo, as features são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Match com base no método HTTP&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /users"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Variavéis no path da requisição&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /users/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Match exato de paths terminados em barra&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// match para qualquer path iniciado com /static/&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /static/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// match somente GET /static/&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /static/{$}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essas mudanças vão reduzir bastante a necessidade de utilizar bibliotecas de routers, e como vai para a stdlib, vai ter a garantia de compatibilidade do Go 1.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Como funciona o &lt;code&gt;http.ServeMux&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;O &lt;code&gt;ServeMux&lt;/code&gt; tem um comportamento diferente da maioria dos routers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Caminhos terminados em barra são como pastas&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/assets/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse handler processa qualquer requisição com prefixo &lt;code&gt;/assets/&lt;/code&gt;, como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /assets/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /assets/img/img.png&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE /assets/abcd&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;O match é feito com o path exato se não for terminado em barra&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/assets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse caso o segundo pattern não termina em barra, então só requisições para exatamente &lt;code&gt;/assets&lt;/code&gt; vão ser processadas por esse handler, e qualquer outra será processada pelo primeiro handler.&lt;/p&gt;

&lt;p&gt;Obs.: O caminho &lt;code&gt;/&lt;/code&gt; dá match em qualquer requisição que não dê match em outro handler, então ele é geralmente usado para a página raiz &lt;strong&gt;e&lt;/strong&gt; página de not found.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O match é feito com o path mais similar&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Se você tiver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/books/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Uma requisição para &lt;code&gt;/users/&lt;/code&gt; vai cair no primeiro handler.&lt;/li&gt;
&lt;li&gt;Uma requisição para &lt;code&gt;/users/123&lt;/code&gt; vai cair no segundo handler.&lt;/li&gt;
&lt;li&gt;Uma requisição para &lt;code&gt;/users/1234&lt;/code&gt; vai cair no primeiro handler.&lt;/li&gt;
&lt;li&gt;Uma requisição para &lt;code&gt;/users/books/123&lt;/code&gt; vai cair no terceiro handler.&lt;/li&gt;
&lt;li&gt;Uma requisição para &lt;code&gt;/users/a/b/c/d&lt;/code&gt; também cai no primeiro handler&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Entendendo o match com base no método HTTP
&lt;/h2&gt;

&lt;p&gt;O comportamento das funções &lt;code&gt;Handle&lt;/code&gt; e &lt;code&gt;HandleFunc&lt;/code&gt; vai se manter igual para códigos existentes por conta da retrocompatibilidade da linguagem, então se você não especificar um método HTTP, seu handler vai continuar dando match em qualquer método.&lt;/p&gt;

&lt;p&gt;Obs.: Um handler para o método GET vai também bater para requisições do método HEAD.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// GET /users&lt;/span&gt;
&lt;span class="c"&gt;// HEAD /users&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /users"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c"&gt;// somente DELETE /users&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DELETE /users"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Utilizando variáveis de path
&lt;/h2&gt;

&lt;p&gt;Podemos capturar o valor de uma variável de path usando o &lt;code&gt;PathValue&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /users/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PathValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Utilizando matches exatos
&lt;/h2&gt;

&lt;p&gt;Ao utilizar o &lt;code&gt;{$}&lt;/code&gt; indicamos que um handler terminado em barra deve somente bater com aquele path, e não com qualquer path com aquele prefixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// redirecionar um request de / para /home&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /{$}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/home"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c"&gt;// qualquer outro path que não de match em outro handler vai dar um not found&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Apesar de simples, essa foi uma mudança bem importante na stdlib do Go, tendo em vista que é uma linguagem muito utilizada para desenvolver servidores Web.&lt;/p&gt;

&lt;p&gt;Mas é claro que essas foram só algumas das muitas novidades do Go 1.22 e pretendo falar de outras que foram bem expressivas, como no &lt;code&gt;for&lt;/code&gt; loop, pacote &lt;code&gt;rand&lt;/code&gt;, e outros em próximos artigos.&lt;/p&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Go: Criando um cache em memória com map, mutex e generics</title>
      <dc:creator>Igor Melo</dc:creator>
      <pubDate>Sun, 03 Dec 2023 19:17:53 +0000</pubDate>
      <link>https://dev.to/igormelo/go-criando-um-cache-em-memoria-com-map-mutex-e-generics-dlb</link>
      <guid>https://dev.to/igormelo/go-criando-um-cache-em-memoria-com-map-mutex-e-generics-dlb</guid>
      <description>&lt;h2&gt;
  
  
  1. Introdução
&lt;/h2&gt;

&lt;p&gt;Nesse artigo vamos desenvolver um cache chave-valor na memória do processo para aprender sobre data races, &lt;code&gt;Mutex&lt;/code&gt;, &lt;code&gt;RWMutex&lt;/code&gt; e generics no Go.&lt;br&gt;
No final vamos fazer comparações de performance para vermos qual é a solução mais eficiente.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Por que não usar simplesmente um &lt;code&gt;map&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;Podemos usar um &lt;code&gt;map&lt;/code&gt; de cache da seguinte forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="c"&gt;// tentando pegar o valor do  cache&lt;/span&gt;
&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"api_lenta/info"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c"&gt;// valor nao esta no cache, tenho que pegar da API&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;consultarAPILenta&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// guardando o valor no cache para o proximo uso&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"api_lenta/info"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// usando o valor, vindo do cache ou da api&lt;/span&gt;
&lt;span class="n"&gt;usarValor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A princípio não tem problema nessa abordagem, porque o cache está sendo usado por uma só goroutine.&lt;br&gt;
O problema começa quando adicionamos múltiplas goroutines...&lt;br&gt;
Vamos falar de data races.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. O que são data races?
&lt;/h2&gt;

&lt;p&gt;Um data race ocorre quando duas ou mais goroutines tentam concorrentemente ler e/ou alterar um dado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No exemplo acima eu crio mil goroutines para incrementar o valor de &lt;code&gt;count&lt;/code&gt;.&lt;br&gt;
Só que eventualmente algumas goroutines vão rodar em paralelo e vão ler e alterar o valor de &lt;code&gt;count&lt;/code&gt; ao mesmo tempo. &lt;/p&gt;

&lt;p&gt;E mesmo que não rodem em paralelo, o &lt;em&gt;scheduler&lt;/em&gt; pode interromper a goroutine no meio da execução dela, antes dela atualizar o valor na memória, e resumir tempo depois, fazendo com que o &lt;code&gt;count&lt;/code&gt; que ela calculou esteja desatualizado.&lt;/p&gt;

&lt;p&gt;Quando isso acontece, não há como determinar qual vai ser o resultado da operação. Tanto que se eu rodar esse programa múltiplas vezes, vou ter resultados diferentes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;go run main.go 
904
&lt;span class="nv"&gt;$ &lt;/span&gt;go run main.go
903
&lt;span class="nv"&gt;$ &lt;/span&gt;go run main.go
958
&lt;span class="nv"&gt;$ &lt;/span&gt;go run main.go
926
&lt;span class="nv"&gt;$ &lt;/span&gt;go run main.go
975
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Regra geral sobre data races
&lt;/h3&gt;

&lt;p&gt;Basicamente podemos pensar da seguinte forma:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Acontece data race quando&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duas ou mais goroutines estão &lt;strong&gt;alterando&lt;/strong&gt; um mesmo valor&lt;/li&gt;
&lt;li&gt;Uma ou mais goroutines estão &lt;strong&gt;lendo&lt;/strong&gt; um valor, enquanto uma goroutine está &lt;strong&gt;alterando&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Não acontece data race quando&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Só há uma goroutine lidando com um dado (lendo ou escrevendo)&lt;/li&gt;
&lt;li&gt;Há múltiplas goroutines lendo um dado (e nenhuma escrevendo)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Em tipos mais complexos, como é o caso do &lt;code&gt;map&lt;/code&gt;, um data race bagunçaria totalmente a estrutura interna dele, então quando ele detecta um data race ele dá um panic com uma das seguintes mensagens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fatal error: concurrent map writes
&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;fatal error: concurrent map read and map write
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Race detector
&lt;/h3&gt;

&lt;p&gt;Felizmente o Go vem com uma ferramenta chamada &lt;em&gt;data race detector&lt;/em&gt; que, como o nome sugere, detecta data races de forma geral e nos diz exatamente as linhas que estão causando o race.&lt;/p&gt;

&lt;p&gt;Para usar o race detector, basta utilizar &lt;code&gt;-race&lt;/code&gt; nos principais comandos do Go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-race&lt;/span&gt; ./...
go run &lt;span class="nt"&gt;-race&lt;/span&gt; arquivo.go
go build &lt;span class="nt"&gt;-race&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se usarmos o race detector no programa que deveria contar até 1000, ele vai detectar o race e mostrar a seguinte mensagem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;go run &lt;span class="nt"&gt;-race&lt;/span&gt; main.go 
&lt;span class="o"&gt;==================&lt;/span&gt;
WARNING: DATA RACE
Read at 0x00c000026178 by goroutine 11:
  main.main.func1&lt;span class="o"&gt;()&lt;/span&gt;
      /projeto/main.go:7 +0x30

Previous write at 0x00c000026178 by goroutine 7:
  main.main.func1&lt;span class="o"&gt;()&lt;/span&gt;
      /projeto/main.go:7 +0x44
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apesar de parecer intimidadora essa saída, a informação relevante é que tivemos um read na linha 7 por uma goroutine e um write na mesma linha 7 por outra goroutine, então nos diz exatamente onde ocorreu o race.&lt;/p&gt;

&lt;p&gt;Sugestões de leitura:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://go.dev/doc/articles/race_detector"&gt;Data Race Detector - The Go Programming Language&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  4. Cache com &lt;code&gt;sync.Mutex&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Como vimos anteriormente, precisamos de alguma forma de evitar data race no map do nosso cache. Para esse tipo de problema existe o conceito de mutex.&lt;/p&gt;

&lt;p&gt;Mutex é um mecanismo para garantirmos que somente uma goroutine tem acesso exclusivo a algo do momento que ela adquire o lock até o momento que ela libera o lock.&lt;/p&gt;

&lt;p&gt;Uma analogia para ficar mais claro:&lt;br&gt;
Pensa em um banheiro. Se não tem nenhuma forma de sincronização, pode acontecer de duas ou mais pessoas usarem o banheiro ao mesmo tempo, o que daria resultados bem desagradáveis.&lt;/p&gt;

&lt;p&gt;A mutex é como se fosse a chave para o banheiro, e quem adquire essa chave se tranca no banheiro e tem acesso exclusivo a ele, enquanto as outras pessoas esperam do lado de fora até que a pessoa termine de usar o banheiro.&lt;/p&gt;

&lt;p&gt;A mutex dá problema quando, ainda na analogia, uma pessoa se tranca no banheiro e não quer mais sair, que é o cenário de &lt;em&gt;deadlock&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Criando um tipo para o Cache e utilizando uma mutex
&lt;/h3&gt;

&lt;p&gt;Para começar vamos criar uma struct para o &lt;code&gt;Cache&lt;/code&gt; com o método &lt;code&gt;Get&lt;/code&gt;, &lt;code&gt;Set&lt;/code&gt; e &lt;code&gt;Delete&lt;/code&gt;, que por enquanto só executa as operações normais do map, sem ser &lt;em&gt;concurrent-safe&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora vamos adicionar a mutex a &lt;code&gt;struct&lt;/code&gt; e ao construtor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;    &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;dataMut&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
        &lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora antes de lermos ou escrevermos no map, precisamos fazer um &lt;code&gt;Lock&lt;/code&gt; para garantirmos que só uma goroutine está lendo/escrevendo, e quando terminarmos, precisamos fazer um &lt;code&gt;Unlock&lt;/code&gt; para permitir que outra goroutine possa fazer o mesmo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E para utilizar o cache:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// "", false&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"somevalue"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// "somevalue", true&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// "", false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sugestões de leitura:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Mutual_exclusion"&gt;Mutual exclusion - Wikipedia&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pkg.go.dev/sync#Mutex"&gt;Documentação da &lt;code&gt;sync.Mutex&lt;/code&gt; - Go Packages&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  5. Introduzindo a &lt;code&gt;sync.RWMutex&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Como falamos antes, podemos ter múltiplas goroutines lendo o mesmo dado sem problemas, desde que não tenha nenhuma escrevendo ao mesmo tempo, porém com a &lt;code&gt;sync.Mutex&lt;/code&gt; só permitimos uma goroutine ler por vez.&lt;/p&gt;

&lt;p&gt;Para permitirmos leituras concorrentes, existe a &lt;code&gt;sync.RWMutex&lt;/code&gt;, onde o "RW" é uma sigla para "read-write".&lt;br&gt;
A &lt;code&gt;RWMutex&lt;/code&gt; nos permite fazer dois tipos de lock e unlock: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;write lock com &lt;code&gt;Lock&lt;/code&gt;, write unlock com &lt;code&gt;Unlock&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;read lock com &lt;code&gt;RLock&lt;/code&gt;. read unlock com &lt;code&gt;RUnlock&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quando precisamos alterar um dado, temos que fazer fazer um &lt;code&gt;Lock&lt;/code&gt; e no fim &lt;code&gt;Unlock&lt;/code&gt;.&lt;br&gt;
Quando só queremos ler um dado sem fazer modificações, podemos fazer um &lt;code&gt;RLock&lt;/code&gt; e no fim um &lt;code&gt;RUnlock&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Atualizando métodos para usar &lt;code&gt;sync.RWMutex&lt;/code&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;    &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;dataMut&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RWMutex&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
        &lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RWMutex&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// write lock&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// read lock&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RLock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RUnlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// write lock&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Sugestões de leitura:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock"&gt;Readers-writers lock&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pkg.go.dev/sync#RWMutex"&gt;Documentação da &lt;code&gt;sync.RWMutex&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  6. Utilizando generics
&lt;/h2&gt;

&lt;p&gt;Até o momento, nosso cache só aceita chaves e valores do tipo &lt;code&gt;string&lt;/code&gt;, mas agora vamos deixar nosso cache mais flexível, aceitando qualquer tipo de chave e valor.&lt;/p&gt;
&lt;h3&gt;
  
  
  Introduzindo a sintaxe de generics
&lt;/h3&gt;

&lt;p&gt;Alguns exemplos de structs genéricas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// a chave do map precisa ser um tipo comparável&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt; &lt;span class="n"&gt;comparable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora um exemplo de função genérica:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora um exemplo de "método" genérico:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Aplicando generics no tipo Cache
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt; &lt;span class="n"&gt;comparable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;    &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;
    &lt;span class="n"&gt;dataMut&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RWMutex&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewCache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt; &lt;span class="n"&gt;comparable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
        &lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RWMutex&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RLock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RUnlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataMut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E agora para usarmos nosso cache genérico:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewCache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"valid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"valid"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Comparações de performance
&lt;/h2&gt;

&lt;p&gt;Comparei o cache utilizando &lt;code&gt;sync.Mutex&lt;/code&gt;, &lt;code&gt;sync.RWMutex&lt;/code&gt;, e um outro tipo que não falei aqui ainda: o &lt;code&gt;sync.Map&lt;/code&gt;.&lt;br&gt;
E para a minha surpresa, a &lt;code&gt;sync.Mutex&lt;/code&gt; performou quase igual a &lt;code&gt;sync.RWMutex&lt;/code&gt;, e até melhor em algumas operações.&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;sync.Map&lt;/code&gt; é um tipo que funciona similar a um &lt;code&gt;map&lt;/code&gt;, mas é &lt;em&gt;concurrent-safe&lt;/em&gt;.&lt;br&gt;
Pela documentação, o &lt;code&gt;sync.Map&lt;/code&gt; é otimizado para leituras concorrentes e leituras e escritas em valores distintos.&lt;/p&gt;

&lt;p&gt;O Resultado do benchmark foi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1000 gets e sets na mesma chave&lt;/span&gt;
sync.Mutex      86908 ns/op
sync.RWMutex   111462 ns/op
sync.Map       239797 ns/op

&lt;span class="c"&gt;# 1000 gets e sets em chaves diferentes&lt;/span&gt;
sync.Mutex      90000 ns/op
sync.RWMutex   115520 ns/op
sync.Map       299608 ns/op

&lt;span class="c"&gt;# 1000 gets e sets concorrentes em chaves diferentes&lt;/span&gt;
sync.Mutex     2238245 ns/op
sync.RWMutex   2856618 ns/op
sync.Map       1884196 ns/op

&lt;span class="c"&gt;# 1000 get concorrentes em chaves diferentes&lt;/span&gt;
sync.Mutex    1074670 ns/op
sync.RWMutex   935320 ns/op
sync.Map       876155 ns/op
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quanto maior o tempo, pior.&lt;/p&gt;

&lt;p&gt;Então podemos concluir que nesses benchmarks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;sync.Mutex&lt;/code&gt; foi mais rápida em gets e sets sequenciais na mesma chave&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;sync.Mutex&lt;/code&gt; foi mais rápida em gets e sets sequenciais em chaves diferentes&lt;/li&gt;
&lt;li&gt;O &lt;code&gt;sync.Map&lt;/code&gt; foi mais rápido em gets e sets concorrentes em chaves distintas&lt;/li&gt;
&lt;li&gt;o &lt;code&gt;sync.Map&lt;/code&gt; foi mais rápido em gets concorrentes (sem sets) em chaves distintas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sugestões de leitura:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://pkg.go.dev/sync#Map"&gt;Documentação do &lt;code&gt;sync.Map&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>go</category>
      <category>tutorial</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>7 vantagens da linguagem Go</title>
      <dc:creator>Igor Melo</dc:creator>
      <pubDate>Sun, 06 Aug 2023 00:28:25 +0000</pubDate>
      <link>https://dev.to/igormelo/7-vantagens-da-linguagem-go-1kg6</link>
      <guid>https://dev.to/igormelo/7-vantagens-da-linguagem-go-1kg6</guid>
      <description>&lt;h2&gt;
  
  
  Antes de tudo
&lt;/h2&gt;

&lt;p&gt;Primeiro, vou fazer uma confissão…&lt;/p&gt;

&lt;p&gt;A primeira vez que vi um código em Go eu achei a linguagem esquisita e me desinteressei.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Como assim não tem try/catch?&lt;/li&gt;
&lt;li&gt;Por que métodos têm essa sintaxe diferente?&lt;/li&gt;
&lt;li&gt;Por que não tem a feature XYZ que "toda" linguagem tem?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essas foram algumas das perguntas que eu me fiz.&lt;br&gt;
Só anos depois que eu resolvi dar uma segunda chance para a linguagem e resolvi aprender.&lt;/p&gt;

&lt;p&gt;Então, antes de tudo, vai um &lt;strong&gt;conselho&lt;/strong&gt;: não foque em detalhes bobos que nem eu fiz.&lt;br&gt;
Uma linguagem tem muito mais a oferecer do que só uma sintaxe “bonita”.&lt;/p&gt;

&lt;p&gt;É muito provável que em Go as coisas sejam diferentes de como você está acostumado a fazer, então não se assuste.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Go é uma linguagem criada por desenvolvedores da Google e lançada a público em 2009.&lt;/p&gt;

&lt;p&gt;A linguagem nasceu com foco em simplicidade, estabilidade e produtividade, pensada para desenvolver aplicações complexas e longevas.&lt;/p&gt;

&lt;p&gt;Nesse artigo vamos ver em detalhes os pontos que eu considero os mais importantes da linguagem.&lt;/p&gt;

&lt;p&gt;Tópicos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrocompatibilidade&lt;/li&gt;
&lt;li&gt;Compilação e portabilidade&lt;/li&gt;
&lt;li&gt;Concorrência&lt;/li&gt;
&lt;li&gt;Biblioteca padrão rica&lt;/li&gt;
&lt;li&gt;Simplicidade&lt;/li&gt;
&lt;li&gt;Ferramenta de profiling de performance nativa&lt;/li&gt;
&lt;li&gt;Ferramenta de testes nativas&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Retrocompatibilidade
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.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%2F0n6ks3hgxk0mlwiauegx.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F0n6ks3hgxk0mlwiauegx.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O Go lançou sua versão estável 1.0 em 2012, com a promessa de que novas versões 1.x.y sejam retrocompatíveis.&lt;br&gt;
Em outras palavras, isso significa que um código em Go escrito em 2012 usando a versão 1.0 deverá compilar e rodar corretamente em 2023 utilizando a versão 1.20.5, por exemplo.&lt;/p&gt;

&lt;p&gt;A Google e muitas outras empresas testam a versão de pré-release do Go nos projetos internos delas para assegurar que a linguagem se manteve compatível e que nada quebrou. A vantagem disso é que se um projeto com milhões de linhas de código de produção e testes não quebraram, é bem improvável que projetos menores vão ter quebrado.&lt;/p&gt;

&lt;p&gt;Porém a promessa de compatibilidade pode ser quebrada em alguns casos, como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Correção de falhas de segurança&lt;/li&gt;
&lt;li&gt;Correção de bugs na linguagem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E alguns outros cenários específicos.&lt;/p&gt;

&lt;p&gt;O mais importante da retrocompatibilidade da linguagem é permitir que desenvolvamos códigos longevos sem precisar estarmos constantemente corrigindo e adaptando o código para as novas mudanças da linguagem.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Compilação e portabilidade
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fskmqlaw7qyw2755yhpah.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fskmqlaw7qyw2755yhpah.jpeg" alt="Gopher compilando código"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na implementação oficial do Go, o código é compilado para um executável com tudo que ele precisa para rodar, o que reduz uma série de dores de cabeça.&lt;/p&gt;

&lt;p&gt;O Go compila e otimiza o código em tempo de build, então o programa não vai utilizar memória nem CPU otimizando seu código em tempo de execução, diferente de como faz o Python, Java, JavaScript, PHP, etc.&lt;/p&gt;

&lt;p&gt;Um detalhe importante é que no Go também é possível compilar para outras arquiteturas. Isso significa que você no Linux num processador ARM pode compilar seu código para rodar em um Windows 64 bits.&lt;br&gt;
Pode não parecer muito, mas em C por exemplo isso não só não é trivial de fazer, como também é desencorajado.&lt;/p&gt;

&lt;p&gt;Exemplo de cross-compiling de um programa Go:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;GOOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;windows &lt;span class="nv"&gt;GOARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;386 go build main.go &lt;span class="c"&gt;# windows 32 bits&lt;/span&gt;
&lt;span class="nv"&gt;GOOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;linux &lt;span class="nv"&gt;GOARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm go build main.go &lt;span class="c"&gt;# linux arm&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  3. Concorrência
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fs8rm39dqapbajnvzsuaf.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fs8rm39dqapbajnvzsuaf.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O Go conta com as goroutines, que são similares a &lt;a href="https://pt.wikipedia.org/wiki/Thread_(computa%C3%A7%C3%A3o)" rel="noopener noreferrer"&gt;threads&lt;/a&gt;, porém são mais leves e gerenciadas pelo &lt;em&gt;runtime&lt;/em&gt; do Go.&lt;/p&gt;

&lt;p&gt;O Go distribui as goroutines pelos núcleos da CPU o que possibilita processarmos coisas em paralelo, e também faz bastante uso de &lt;a href="https://en.wikipedia.org/wiki/Asynchronous_I/O" rel="noopener noreferrer"&gt;I/O assíncrono&lt;/a&gt;, o que possibilita um ganho considerável de performance em aplicações que façam muito uso de I/O, como aplicações web.&lt;/p&gt;

&lt;p&gt;A linguagem também conta com canais (channels), que são uma ferramenta poderosa para comunicar e sincronizar goroutines.&lt;br&gt;
Channels é um tópico tão importante da linguagem que eu fiz &lt;a href="https://dev.to/igormelo/golang-desmistificando-channels-4n7h"&gt;uma série de 5 artigos&lt;/a&gt; dedicada a eles. &lt;/p&gt;
&lt;h2&gt;
  
  
  4. Biblioteca padrão rica
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.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%2F8a4sj8l77rbb3gcpy0hh.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F8a4sj8l77rbb3gcpy0hh.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O Go vem com uma biblioteca bem rica de pacotes que você pode utilizar em suas aplicações.&lt;br&gt;
Esses são apenas alguns exemplos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;io&lt;/code&gt;: para lidar com leitura, escrita, etc de bytes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;os&lt;/code&gt;: para lidar com o OS (arquivos, env, processos, etc)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;time&lt;/code&gt;: para obter, converter e formatar tempo&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;testing&lt;/code&gt;: para testes automatizados, incluindo benchmark e fuzzing&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;crypto&lt;/code&gt;: para algoritmos e constantes criptográficas&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;net&lt;/code&gt;: para lidar com TCP, UDP, DNS&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;net/http&lt;/code&gt;: para clientes e servidores HTTP 1 e 2&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;html/template&lt;/code&gt;: template engine para HTML&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  5. Simplicidade
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.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%2F54k59wygke0cjuo3spcg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F54k59wygke0cjuo3spcg.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Muita gente se assusta quando ouve alguém falar que "C é uma linguagem muito simples".&lt;br&gt;
Mas quando alguém fala que "C é simples" não significa que programar em C é moleza, mas sim que a linguagem em si é mais minimalista, não possui muitas formas diferentes de fazer a mesma coisa, não tem muito comportamento implícito, etc.&lt;/p&gt;

&lt;p&gt;Alguns exemplos de como esse princípio é aplicado no Go:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Idealmente só há uma forma de fazer algo&lt;/li&gt;
&lt;li&gt;O equivalente a "constructors" e "destructors" são explícitos&lt;/li&gt;
&lt;li&gt;A linguagem possui apenas 25 palavras reservadas (vs 67 do Java, 95 do C++)&lt;/li&gt;
&lt;li&gt;A especificação tem cerca de 100 páginas (vs +800 do Java, +1800 do C++)&lt;/li&gt;
&lt;li&gt;A stdlib evita o uso de abstrações e indireções quando não é necessário&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Obs.: Java e C++ foram citados só para fins de comparação&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A vantagem de uma linguagem simples é que você se dedica menos tempo aprendendo a linguagem em si, e mais tempo desenvolvendo e aprendendo conceitos mais importantes.&lt;/p&gt;
&lt;h2&gt;
  
  
  6. Ferramenta de profiling de performance nativa
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fnkwhy042vbu2sgos4o92.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fnkwhy042vbu2sgos4o92.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Não deixei esse tópico como um dos primeiros porque a maioria das soluções tem uma performance "boa o suficiente" para maioria dos cenários, e otimizações costumam ser bem pontuais.&lt;/p&gt;

&lt;p&gt;Porém, quando sua aplicação tem milhões de usuários diariamente batendo em endpoints, uma linguagem que usa pouca memória e consegue gerenciar milhares de requisições por segundo é um diferencial.&lt;/p&gt;

&lt;p&gt;O Go conta com uma ferramenta nativa para medir uso de memória, CPU, goroutines, e muito mais, o que te permite otimizar performance com base em métricas em vez de suposições.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F414mpvdd0v20u0wecmcv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F414mpvdd0v20u0wecmcv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F4ykpulpnd471y9lr599a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F4ykpulpnd471y9lr599a.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Além disso, desde a versão 1.20, o Go suporta &lt;a href="https://go.dev/doc/pgo" rel="noopener noreferrer"&gt;Profile-guided optimization (PGO)&lt;/a&gt;, que é utilizar dados obtidos num profile de performance como parâmetro para otimizar o código durante a compilação.&lt;/p&gt;
&lt;h2&gt;
  
  
  7. Ferramenta de testes nativas
&lt;/h2&gt;

&lt;p&gt;O Go vem com suporte nativo a testes automatizados, fuzzing e benchmarking.&lt;/p&gt;

&lt;p&gt;Com testes automatizados você pode validar que seu código está sempre se comportando como esperado.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestFormatarNomeDeCartao&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"Zezinho da Silva Freitas Junior"&lt;/span&gt;
    &lt;span class="n"&gt;esperado&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"Zezinho da S F Junior"&lt;/span&gt;

    &lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;FormatarNomeDeCartao&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;esperado&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"esperado: %s, obtido: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;esperado&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;Com testes de fuzzing você alimenta o teste com um valor inicial, que no nosso exemplo vai ser um nome, e o fuzzer vai começar a criar variações desse valor e chamar sua função com eles.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;FuzzFormatarNomeDeCartao&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Zezinho da Silva"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fuzz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;FormatarNomeDeCartao&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultado&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"O nome abreviado '%s' está maior que o original '%s'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Com testes de benchmark você pode verificar o tempo médio que uma função leva para rodar, uso de memória, alocações etc.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;BenchmarkFormatarNomeDeCartao&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;FormatarNomeDeCartao&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Zezinho da Silva Freitas Junior"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Go: Analisando performance com pprof</title>
      <dc:creator>Igor Melo</dc:creator>
      <pubDate>Fri, 26 May 2023 19:31:47 +0000</pubDate>
      <link>https://dev.to/igormelo/go-analisando-performance-com-pprof-1io</link>
      <guid>https://dev.to/igormelo/go-analisando-performance-com-pprof-1io</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;O &lt;code&gt;pprof&lt;/code&gt; (Performance Profiler) é uma ferramenta que vem com o Go e que serve para extrair dados de performance, como uso de CPU, alocação de memória, goroutines, entre outros.&lt;/p&gt;

&lt;p&gt;A grande utilidade do &lt;code&gt;pprof&lt;/code&gt; é que ele nos diz exatamente onde no nosso código os recursos estão sendo utilizados, ou seja, conseguimos achar com facilidade as funções que estão usando mais CPU ou mais memória, e até conseguimos ver a linha exata do código que está causando o problema de performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mX4aWeUw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3yhfsiug18eqdqhe9t4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mX4aWeUw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3yhfsiug18eqdqhe9t4m.png" alt=" raw `pprof` endraw  mostrando em qual linha há um tempo considerável sendo gasto" width="758" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Aplicação de exemplo
&lt;/h2&gt;

&lt;p&gt;Vou usar como exemplo esse código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"argumentos invalidos"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O que ele faz é simples: copia o conteúdo de um arquivo para outro arquivo, similar ao que o comando &lt;a href="https://www.man7.org/linux/man-pages/man1/cp.1.html"&gt;&lt;code&gt;cp&lt;/code&gt;&lt;/a&gt; faz.&lt;br&gt;
Claro que é só um exemplo bobo comparado a aplicações reais, mas é suficiente para  praticarmos.&lt;/p&gt;

&lt;p&gt;Esse programa tem um problema... Se eu tento copiar um arquivo muito grande, o uso de memória aumenta em mais de 3GB:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4bpLOfaU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ityu2jlzpjdxcyh41x8b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4bpLOfaU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ityu2jlzpjdxcyh41x8b.png" alt="Image description" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Por que isso acontece? Vamos investigar.&lt;/p&gt;
&lt;h2&gt;
  
  
  Fazendo o profiling
&lt;/h2&gt;

&lt;p&gt;A forma mais prática de fazer o profiling de CPU e memória é criando um teste comum ou de benchmark.&lt;br&gt;
Para isso vou criar um arquivo &lt;code&gt;main_test.go&lt;/code&gt; e vou adicionar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"testing"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Test_main_CopyManjaro&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// injetando os argumentos para o programa funcionar&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"gp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"manjaro.iso"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"manjaro2.iso"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E daí, se executarmos:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Ele vai só rodar os testes nesse pacote.&lt;/p&gt;

&lt;p&gt;Já para extraírmos os profiles, fazemos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go test -cpuprofile cpu.prof -memprofile mem.prof .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Analisando os dados de memória
&lt;/h2&gt;

&lt;p&gt;Agora que extraímos os dados que queríamos, vamos analisar na ferramenta web do &lt;code&gt;pprof&lt;/code&gt;.&lt;br&gt;
Para isso, basta executar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go tool pprof -http :8080 mem.prof
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E ele vai abrir o profile de memória no seu navegador padrão.&lt;/p&gt;

&lt;p&gt;Esse gráfico pode parecer meio intimidador a primeira vista, mas basicamente ele está nos dizendo quais funções chamam quais, e quais usam mais memória:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EFMSHvV2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ccm8e30p5tmwuuxqia65.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EFMSHvV2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ccm8e30p5tmwuuxqia65.png" alt="Visão de grafo de profiling de memória" width="800" height="871"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se seguirmos o gráfico, a função &lt;code&gt;tRunner&lt;/code&gt; (do pacote de testes) chama &lt;code&gt;Test_main&lt;/code&gt;, que chama a &lt;code&gt;main&lt;/code&gt;, e a &lt;code&gt;main&lt;/code&gt; chama &lt;code&gt;os.ReadFile&lt;/code&gt;, sendo esse último quem aloca nesse caso 3.82GB.&lt;/p&gt;

&lt;p&gt;Indo em &lt;em&gt;View&lt;/em&gt; e trocando a visualização para &lt;em&gt;Top&lt;/em&gt; chegamos na mesma conclusão.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cRVXN6A5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9biilhfj32szs7mzeobr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cRVXN6A5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9biilhfj32szs7mzeobr.png" alt="Image description" width="596" height="236"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Otimizando com base no profiling de memória
&lt;/h2&gt;

&lt;p&gt;Descobrimos que a função &lt;code&gt;os.ReadFile&lt;/code&gt; é a causadora do problema de uso de memória, porque estamos lendo todo o arquivo em memória e só então escrevendo o conteúdo num novo arquivo.&lt;/p&gt;

&lt;p&gt;A solução é ler pedaço por pedaço do arquivo e ir escrevendo em outro arquivo, e para isso podemos usar a função &lt;code&gt;io.Copy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O código vai ficar assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"io"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"argumentos invalidos"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E o resultado do uso de memória, olhando pelo gerenciador de tarefas é:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fGkCSuT7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mgn4fd7axuzys8x0j6hu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fGkCSuT7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mgn4fd7axuzys8x0j6hu.png" alt="Image description" width="800" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Analisando um profiling de CPU
&lt;/h2&gt;

&lt;p&gt;O profiling de CPU desse caso não vai nos dar muita informação interessante, por ser um código extremamente simples, então vou usar um exemplo de outro projeto que fiz para um desafio.&lt;/p&gt;

&lt;p&gt;O projeto em questão envolve ler um arquivo e inserir os dados de cada linha num banco Postgres.&lt;/p&gt;

&lt;p&gt;O meu programa estava levando 37 segundos para processar 50 mil linhas, então resolvi fazer o profiling de CPU para investigar.&lt;br&gt;
Eu fiz o profiling de CPU e abri o pprof na aba de &lt;em&gt;Flame Graph (new)&lt;/em&gt;.&lt;br&gt;
Essa aba nos mostra quais funções estão levando mais tempo para executar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aJIh7LHz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c2z28c2iv6wt984eu5dx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aJIh7LHz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c2z28c2iv6wt984eu5dx.png" alt="flame graph do CPU" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pode parecer intimidador, mas em resumo o que o gráfico diz para nós é que a função &lt;code&gt;main.main&lt;/code&gt; chama diversas funções, como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pgx.(*Conn).Exec&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;main.CustomerFrom&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Fields&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E as funções mais "largas" são as que estão tomando mais tempo para serem executadas, e nesse caso é a &lt;code&gt;pgx.(*Conn).Exec&lt;/code&gt;.&lt;br&gt;
Essa função é a que executa a inserção no banco Postgres.&lt;/p&gt;

&lt;p&gt;Pesquisando sobre Postgres e estudando a lib &lt;code&gt;pgx&lt;/code&gt; eu descobri que uma possível solução era enviar várias inserções de uma vez (chamado de batch), e resolvi experimentar e fazer um novo profiling.&lt;br&gt;
O resultado foi: &lt;strong&gt;queda de 37s para 2s no tempo de execução&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7XC0Xtg8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y1nagl7f5ge8oc4lb3d4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7XC0Xtg8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y1nagl7f5ge8oc4lb3d4.png" alt="queda de 37s para 2s no tempo de execução" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Veja que a função &lt;code&gt;pgx.(*Conn).SendBatch&lt;/code&gt; e &lt;code&gt;Exec&lt;/code&gt; estão tomando uma fatia muito menor do tempo, e o que estava lento agora era a serialização e desserialização de dados.&lt;/p&gt;

&lt;h2&gt;
  
  
  E em aplicações que "não param"?
&lt;/h2&gt;

&lt;p&gt;Até agora as técnicas de profiling que vimos só vão servir para aplicações que encerram rápido, como scripts, ferramentas de terminal, etc.&lt;/p&gt;

&lt;p&gt;Para aplicações que rodam por tempo indeterminado, como servidores e interfaces gráficas, vamos precisar de outra abordagem para fazer esse profiling.&lt;/p&gt;

&lt;p&gt;Para manter esse artigo simples e leve, vamos abordar essas técnicas na parte 2.&lt;br&gt;
A parte 1 é mais para te dar uma noção de como funciona profiling em Go e como identificar problemas de performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Espero que essa primeira parte tenha te dado uma boa noção de como fazer profiling em Go e também tenha te esclarecido a importância de mensurar antes de otimizar, pois sem métricas você não tem como priorizar o que precisa ser otimizado e vai acabar gastando bastante energia otimizando coisas que não precisam tanto assim.&lt;/p&gt;

&lt;p&gt;Aguarde a segunda parte para falarmos como analisar performance de aplicações web e similares, onde como já falamos, são aplicações que rodam por tempo indeterminado e precisam de estratégias diferentes para mensurar performance.&lt;/p&gt;

</description>
      <category>go</category>
      <category>tutorial</category>
      <category>programming</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Git para leigos</title>
      <dc:creator>Igor Melo</dc:creator>
      <pubDate>Sun, 19 Mar 2023 18:51:02 +0000</pubDate>
      <link>https://dev.to/igormelo/git-para-leigos-2ml6</link>
      <guid>https://dev.to/igormelo/git-para-leigos-2ml6</guid>
      <description>&lt;p&gt;O Git hoje é uma ferramenta fundamental para praticamente todos os desenvolvedores.&lt;br&gt;
Nesse artigo você irá entender de forma simplificada como o Git funciona, sua aplicabilidade e alguns comandos essenciais.&lt;br&gt;
Não veremos ainda como utilizar GitHub pois isso geraria mais confusão para quem tá começando e não entende ainda como o Git funciona.&lt;/p&gt;
&lt;h2&gt;
  
  
  Todo mundo já fez algo assim
&lt;/h2&gt;

&lt;p&gt;Seja algum trabalho da escola, TCC, ou mesmo algum projeto de programação, você com certeza já deve ter feito isso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;trabalho de historia.docx
trabalho de historia2.docx
trabalho de historia3.docx
trabalho de historia FINAL.docx
trabalho de historia FINAL DE VERDADE.docx
trabalho de historia FINAL AGORA EH PRA VALER.docx
trabalho de historia FINAL CORRECOES.docx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basicamente evitamos sobrescrever o arquivo por temos medo de alterar demais e não conseguir voltar a versão anterior.&lt;/p&gt;

&lt;p&gt;Para isso há décadas surgiram vários sistemas de controle de versão, que são ferramentas que te ajudam a registrar versões, que são pontos no histórico de alterações em arquivos, basicamente.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é o Git
&lt;/h2&gt;

&lt;p&gt;Eu gosto de pensar no Git como uma “máquina do tempo de arquivos”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Famjathw1yf6644wdvbau.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Famjathw1yf6644wdvbau.png" alt="Histórico do Git"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A figura acima é um exemplo de histórico de alterações, como se fosse uma linha do tempo.&lt;/p&gt;

&lt;p&gt;Com essa “máquina” conseguimos ver como um arquivo estava no passado, desfazer alterações, criar “realidades alternativas” onde o mesmo arquivo pode ser alterado de formas diferentes, desfazer alterações e muito mais.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fl14tpypnwmdcsmak02s0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fl14tpypnwmdcsmak02s0.png" alt="Histórico do Git com realidade alternativa"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na figura, em amarelo está o histórico principal, enquanto em azul é um histórico alternativo onde um tema está sendo desenvolvido. Quando esse tema é finalizado ele é combinado ao histórico principal.&lt;br&gt;
Não se preocupe em entender esse conceito agora.&lt;/p&gt;

&lt;p&gt;O Git se torna útil por uma série de motivos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Você não precisa ficar criando cópias de arquivos para não perder suas alterações&lt;/li&gt;
&lt;li&gt;O Git utiliza pouco armazenamento e é bem rápido&lt;/li&gt;
&lt;li&gt;É ótimo para trabalhar com arquivos em formato texto, como código, arquivos de configuração, arquivos de projetos, etc&lt;/li&gt;
&lt;li&gt;Tendo um histórico bem definido de alterações, é muito mais fácil entender o que foi alterado e reverter algo se necessário&lt;/li&gt;
&lt;li&gt;Facilita o trabalho em equipe, sendo possível combinar o trabalho de múltiplas pessoas com detecção automática de conflitos&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Instalando o Git
&lt;/h2&gt;

&lt;p&gt;Siga as instruções de instalação para o seu sistema. Para o Windows, instale com as opções padrões.&lt;/p&gt;
&lt;h3&gt;
  
  
  Windows
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://git-scm.com/download/win" rel="noopener noreferrer"&gt;Git - Downloading Package&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Linux
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://git-scm.com/download/linux" rel="noopener noreferrer"&gt;Git&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Mac
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://git-scm.com/download/mac" rel="noopener noreferrer"&gt;Git - Downloading Package&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Seu primeiro projeto com Git
&lt;/h2&gt;

&lt;p&gt;A melhor forma de aprender qualquer coisa é pondo em prática. Para isso vamos iniciar um projeto com Git.&lt;/p&gt;

&lt;p&gt;Vamos criar um projeto do zero exclusivamente para treinar Git, pois assim vamos ficar mais a vontade de fazer alterações e executar comandos sem medo de perder algo de importante.&lt;/p&gt;

&lt;p&gt;Para isso:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Abra um terminal, no caso de Linux ou Mac, ou o Git Bash, no caso de Windows&lt;/li&gt;
&lt;li&gt;Digite &lt;code&gt;mkdir aprendendo-git&lt;/code&gt; e aperte Enter para criar uma pasta&lt;/li&gt;
&lt;li&gt;Digite &lt;code&gt;cd aprendendo-git&lt;/code&gt; e aperte Enter para entrar na pasta que criou&lt;/li&gt;
&lt;li&gt;Agora que está na pasta certa, digite &lt;code&gt;git init&lt;/code&gt; e aperte Enter&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Seu resultado deve ser algo similar a isso:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F7tx0rsmqtbwdu9yydvla.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F7tx0rsmqtbwdu9yydvla.png" alt="Criando um repositório git"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Com o comando &lt;code&gt;git init&lt;/code&gt; nós inicializamos um &lt;strong&gt;repositório&lt;/strong&gt; na pasta oculta &lt;code&gt;.git&lt;/code&gt;.&lt;br&gt;
Um repositório é um local onde diversas informações, inclusive os registros de histórico, são guardadas.&lt;br&gt;
O repositório só vai analisar os arquivos dentro dessa pasta &lt;code&gt;aprendendo-git&lt;/code&gt; e das subpastas, exceto a &lt;code&gt;.git&lt;/code&gt; em si.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tome cuidado!&lt;/strong&gt; Se você apagar a pasta &lt;code&gt;.git&lt;/code&gt;, você perderá todo o histórico que foi registrado.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  O comando &lt;code&gt;git status&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Este é um comando que iremos utilizar com bastante frequência, pois ele nos lista quais arquivos foram criados, alterados, apagados e essa alteração ainda não foi registrada no histórico.&lt;/p&gt;

&lt;p&gt;Como no projeto que acabamos de criar ainda não tem nenhum arquivo, se rodarmos o comando &lt;code&gt;git status&lt;/code&gt;, vamos ter a seguinte saída:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fsa6aeablqs0uqqvjafi5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fsa6aeablqs0uqqvjafi5.png" alt="Saída do git status sem nenhuma alteração"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basicamente está sendo dito que não tem nenhuma alteração para registrar.&lt;/p&gt;

&lt;p&gt;Vamos então criar um arquivo na pasta &lt;code&gt;aprendendo-git&lt;/code&gt; utilizando o editor de sua preferência.&lt;/p&gt;

&lt;p&gt;Agora se rodarmos &lt;code&gt;git status&lt;/code&gt; de novo, vamos ter uma saída diferente:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fn1ly5x4f0odr96ivelks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fn1ly5x4f0odr96ivelks.png" alt="Saída do git status quando tem alguma alteração"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O arquivo que criei está com status &lt;strong&gt;untracked&lt;/strong&gt;, que significa que o Git nunca registrou esse arquivo no histórico.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Obs.: o vermelho no arquivo não significa que algo está errado. O Git usa apenas para distinguir o status&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Gravando alterações no histórico
&lt;/h2&gt;

&lt;p&gt;Uma coisa importante para quem tá começando é que &lt;strong&gt;o Git não registra histórico por conta própria&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Se você fizer uma alteração e desfazer sem explicitamente registrar no Git, essa alteração vai ser perdida.&lt;/p&gt;

&lt;p&gt;Para gravar uma alteração, precisamos seguir este fluxo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F5rurd9ix83g2knqnart6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F5rurd9ix83g2knqnart6.png" alt="Fazer alteração -&amp;gt; Preparar alteração -&amp;gt; Registrar alteração"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Fazer alteração
&lt;/h3&gt;

&lt;p&gt;Esse é o passo mais simples e já fizemos. Basta criar um arquivo dentro do projeto utilizando qualquer programa.&lt;/p&gt;

&lt;p&gt;Alterações nesse estágio são chamadas de alterações não-preparadas (&lt;strong&gt;unstaged&lt;/strong&gt;) e são representadas no Git pela cor vermelha.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Preparar alteração
&lt;/h3&gt;

&lt;p&gt;Esse passo antes de registrar a alteração nos dá maior flexibilidade, porque podemos ter 10 arquivos alterados, mas só 3 que queremos registrar no momento.&lt;br&gt;
Alterações nesse estágio são chamadas de preparadas (&lt;strong&gt;staged&lt;/strong&gt;) e são representadas no Git pela cor verde.&lt;/p&gt;

&lt;p&gt;Para preparar todas as alterações em um arquivo, basta rodar o comando &lt;code&gt;git add &amp;lt;arquivo&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Se olharmos o &lt;code&gt;git status&lt;/code&gt; depois disso, vamos ver que agora o arquivo está com um status diferente e cor verde:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fq4vzohdygxy1fucx6we5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fq4vzohdygxy1fucx6we5.png" alt="Status de um arquivo preparado"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Registrar alteração
&lt;/h3&gt;

&lt;p&gt;Até o momento, nenhuma alteração que fizemos foi de fato “salva” no repositório.&lt;br&gt;
Para registrar nossas alterações &lt;strong&gt;preparadas&lt;/strong&gt; (&lt;strong&gt;staged&lt;/strong&gt;), nós vamos usar o comando &lt;code&gt;git commit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Esse comando cria um &lt;strong&gt;commit&lt;/strong&gt;, que nada mais é do que um registro no histórico do Git.&lt;br&gt;
A partir de agora vou passar a chamar “registro” de commit para você se acostumar com o termo.&lt;/p&gt;

&lt;p&gt;Um commit por padrão exige uma mensagem resumindo o que essas alterações fazem e o porquê.&lt;br&gt;
Podemos passar a mensagem utilizando a opção &lt;code&gt;-m&lt;/code&gt; do comando commit, da seguinte forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s1"&gt;'criando um exemplo'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.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%2Fy4u47scbn6e0ye8qft37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fy4u47scbn6e0ye8qft37.png" alt="Erro ao fazer commit por não ter nome e email"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Obtemos um erro porque &lt;strong&gt;não temos nome e email&lt;/strong&gt; configurado no Git.&lt;/p&gt;

&lt;p&gt;Todo commit no Git precisa dessas duas informações. Vamos fazer o sugerido e configurar nosso nome e email global.&lt;br&gt;
Não existe nenhuma validação nisso, então eu posso botar qualquer email e nome:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# com o --global: todos os projetos irão usar essas credenciais por padrão&lt;/span&gt;
config &lt;span class="nt"&gt;--global&lt;/span&gt; user.email &lt;span class="s2"&gt;"igor@eu.com"&lt;/span&gt;
config &lt;span class="nt"&gt;--global&lt;/span&gt; user.name &lt;span class="s2"&gt;"Igor"&lt;/span&gt;

&lt;span class="c"&gt;# sem o --global: cada projeto terá que configurar seu próprio user.email e user.name&lt;/span&gt;
config user.email &lt;span class="s2"&gt;"igor@eu.com"&lt;/span&gt;
config user.name &lt;span class="s2"&gt;"Igor"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora se tentarmos de novo, irá funcionar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fmhvwjetjlr9nfs8k2vn1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fmhvwjetjlr9nfs8k2vn1.png" alt="Commit sendo feito depois de configurar email e senha"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pronto!&lt;br&gt;
Fizemos nosso primeiro commit. &lt;/p&gt;

&lt;p&gt;Agora vamos checar o status de novo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fmp7fxpw40qw7kxwx3yn2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fmp7fxpw40qw7kxwx3yn2.png" alt="Status após fazer um commit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E vamos novamente modificar o arquivo &lt;code&gt;exemplo.txt&lt;/code&gt; e olhar o status:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fuh4g6l5zac3th3fdwfit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fuh4g6l5zac3th3fdwfit.png" alt="Status de modified no arquivo exemplo.txt"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repare que o status dessa vez é &lt;strong&gt;modified&lt;/strong&gt;, porque agora o arquivo já tem histórico no Git.&lt;/p&gt;
&lt;h2&gt;
  
  
  Vendo o histórico de commits e as alterações feitas
&lt;/h2&gt;

&lt;p&gt;Há várias formas de fazer isso, mas para simplificar, vou usar um único comando: &lt;code&gt;git log -p&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;git log&lt;/code&gt; lista os commits na ordem dos mais recentes para os mais antigos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fsjt9c63feg208x5myuqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fsjt9c63feg208x5myuqb.png" alt="Saída do git log"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Várias informações são mostradas&lt;/strong&gt;, mas as mais importantes por agora são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Autor (nome e email)&lt;/li&gt;
&lt;li&gt;Data&lt;/li&gt;
&lt;li&gt;Mensagem (criando um exemplo)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para sair dessa visualização apertamos &lt;code&gt;q&lt;/code&gt; e podemos mover na vertical com as setas ou scroll do mouse.&lt;/p&gt;

&lt;p&gt;Se adicionarmos a opção &lt;code&gt;-p&lt;/code&gt;, esse vai ser o resultado:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fwde7rlfvrl6sub9wd4wz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fwde7rlfvrl6sub9wd4wz.png" alt="Saída do git log -p"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;De novo, aqui vemos várias informações sendo mostradas, mas as mais relevantes são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mensagem, para entender o contexto das alterações&lt;/li&gt;
&lt;li&gt;Nome do arquivo que foi alterado, depois do &lt;code&gt;+++&lt;/code&gt; (ignore o &lt;code&gt;a/&lt;/code&gt; e o &lt;code&gt;b/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;O texto em verde com prefixo &lt;code&gt;+&lt;/code&gt;, que significa que aquela linha foi adicionada&lt;/li&gt;
&lt;li&gt;Linhas em vermelho com prefixo &lt;code&gt;-&lt;/code&gt; significa que foram removidas&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Exemplo mais concreto
&lt;/h2&gt;

&lt;p&gt;Vamos criar um projeto do zero de novo, mas dessa vez vamos fazer algo menos abstrato para você ter uma sensação de como é usar Git para um projeto real.&lt;/p&gt;

&lt;p&gt;Vou criar um projeto em HTML, mas não é requisito saber.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Iniciando o projeto
&lt;/h3&gt;

&lt;p&gt;Vamos sair da pasta &lt;code&gt;aprendendo-git&lt;/code&gt; vamos criar uma nova pasta &lt;code&gt;padaria&lt;/code&gt; e vamos entrar nela:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd
mkdir &lt;/span&gt;padaria
&lt;span class="nb"&gt;cd &lt;/span&gt;padaria
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos iniciar um repositório Git:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Primeiro commit
&lt;/h3&gt;

&lt;p&gt;Agora vamos começar a criar a página principal, &lt;code&gt;index.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Bem-vindo a Padaria Rubrum Panem&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
    Ipsum quo quia voluptatem quibusdam. Minima eos animi
    dignissimos consequuntur qui optio distinctio possimus.
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quando sentirmos que já temos um básico feito, já podemos fazer nosso primeiro commit.&lt;/p&gt;

&lt;p&gt;Primeiro adicionamos o arquivo index.html:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E em seguida fazemos um commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s1"&gt;'página principal'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Commit de nova funcionalidade
&lt;/h3&gt;

&lt;p&gt;Agora resolvemos criar uma página de contato, &lt;code&gt;contato.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Contato&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Telefone: (99) 99999-9999&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Email: contato@padaria.com&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Endereço: Rua da Padaria, 123 - Osasco&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E criamos um link na &lt;code&gt;index.html&lt;/code&gt; para a página &lt;code&gt;contato.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;...
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/contato.html"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Contato&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Faz sentido que ambas as alterações sejam adicionadas a um mesmo commit, já que estão totalmente relacionadas. Sem a alteração do &lt;code&gt;index.html&lt;/code&gt; o usuário não tem link para a página de contato, então vamos adicionar os dois arquivos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add index.html contato.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos olhar o status para confirmar que os dois arquivos foram adicionados:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fhfpinkl26x9evb6ruhfc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fhfpinkl26x9evb6ruhfc.png" alt="Verificando o status depois de um git add"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E agora fazemos o commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s1"&gt;'página de contato'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Revendo os commits feitos
&lt;/h3&gt;

&lt;p&gt;Se rodarmos o comando &lt;code&gt;git log -p&lt;/code&gt; que aprendemos antes, o resultado será:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fkp1c27y4n48qxt6ngptn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fkp1c27y4n48qxt6ngptn.png" alt="Saída do git log -p após o segundo commit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E rolando para baixo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fx321hfmoorkbscbf54ts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fx321hfmoorkbscbf54ts.png" alt="Saída do git log -p após o segundo commit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Com isso já podemos concluir a primeira parte, mas não se iluda, isso é apenas o começo!&lt;br&gt;
Pratique bastante, pois mais para frente você vai aprender a reverter commits, combinar commits, criar branches, trabalhar com remotes como GitHub, criar pull requests, e muito mais.&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>git</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Implementando um cat em C</title>
      <dc:creator>Igor Melo</dc:creator>
      <pubDate>Mon, 23 Jan 2023 14:09:07 +0000</pubDate>
      <link>https://dev.to/igormelo/implementando-um-cat-em-c-5g14</link>
      <guid>https://dev.to/igormelo/implementando-um-cat-em-c-5g14</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;O &lt;code&gt;cat&lt;/code&gt; é uma ferramenta muito utilizada para ler e escrever em arquivos.&lt;/p&gt;

&lt;p&gt;Ela faz parte do Coreutils, que é um conjunto de utilitários para manipular arquivos, shell e texto, como &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;chmod&lt;/code&gt;, &lt;code&gt;mkdir&lt;/code&gt;, &lt;code&gt;cd&lt;/code&gt;, entre outros.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplos de utilização do &lt;code&gt;cat&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Ler um arquivo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;arquivo.txt
Esse
é
o 
conteúdo!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ler mais de um arquivo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;arquivo1.txt arquivo2.txt
Conteúdo &lt;span class="k"&gt;do &lt;/span&gt;arquivo 1
Conteúdo &lt;span class="k"&gt;do &lt;/span&gt;arquivo 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Entendendo &lt;code&gt;stdin&lt;/code&gt;, &lt;code&gt;stdout&lt;/code&gt; e &lt;code&gt;stderr&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Esses três são streams de dados, ou seja, são um “caminho” por onde dado é recebido ou enviado.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;stdin&lt;/code&gt; representa a &lt;strong&gt;entrada padrão&lt;/strong&gt; (&lt;strong&gt;st&lt;/strong&gt;an*&lt;em&gt;d&lt;/em&gt;&lt;em&gt;ard **in&lt;/em&gt;*put) do programa, que no terminal geralmente é o teclado.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;stdout&lt;/code&gt; representa a &lt;strong&gt;saída padrão&lt;/strong&gt; (*&lt;strong&gt;&lt;em&gt;st&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;an&lt;/em&gt;&lt;em&gt;d&lt;/em&gt;&lt;em&gt;ard *&lt;/em&gt;*&lt;strong&gt;&lt;em&gt;out&lt;/em&gt;&lt;/strong&gt;&lt;strong&gt;*put) do programa, e &lt;code&gt;stderr&lt;/code&gt; representa a **saída padrão de erro&lt;/strong&gt; (*&lt;strong&gt;&lt;em&gt;st&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;an&lt;/em&gt;&lt;em&gt;d&lt;/em&gt;&lt;em&gt;ard *&lt;/em&gt;*&lt;strong&gt;&lt;em&gt;err&lt;/em&gt;&lt;/strong&gt;***or), sendo que ambas são geralmente a tela do terminal.&lt;/p&gt;

&lt;p&gt;O “geralmente” é usado por 2 motivos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Essas 3 streams podem ser redirecionadas para arquivos e outros lugares&lt;/li&gt;
&lt;li&gt;Em aparelhos como um Arduino a entrada pode vir de sensores e a saída pode ser para um display&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Detalhe: no C, &lt;code&gt;stdin&lt;/code&gt;, &lt;code&gt;stdout&lt;/code&gt; e &lt;code&gt;stderr&lt;/code&gt; são arquivos, então lidamos com eles da mesma forma que lidaríamos com qualquer outro arquivo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Redirecionando streams no terminal
&lt;/h3&gt;

&lt;p&gt;Ainda no exemplo do &lt;code&gt;cat&lt;/code&gt;, se rodarmos somente o comando sem nenhum argumento, o que ele faz é ler do &lt;code&gt;stdin&lt;/code&gt; e escrever no &lt;code&gt;stdout&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat
&lt;/span&gt;oi            &lt;span class="c"&gt;# eu escrevi&lt;/span&gt;
oi            &lt;span class="c"&gt;# cat printou&lt;/span&gt;
tudo bem?     &lt;span class="c"&gt;# eu escrevi&lt;/span&gt;
tudo bem?     &lt;span class="c"&gt;# cat printou&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A princípio pode parecer meio sem utilidade o &lt;code&gt;cat&lt;/code&gt; ”imitar” o que você escreve, mas isso se torna útil quando você redireciona a saída para um arquivo usando o &lt;code&gt;&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; novo.txt
Escrevendo o
conteúdo
desse arquivo
&lt;span class="c"&gt;# aperte ctrl + D para finalizar&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &amp;lt; original.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; copia.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Iniciando a implementação em C usando &lt;code&gt;stdio.h&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Agora que os conceitos de entrada e saída padrão já estão mais claros, podemos começar a implementar o código do nosso &lt;code&gt;cat&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para isso vamos partir dessa estrutura básica:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;

int main&lt;span class="o"&gt;(&lt;/span&gt;int argc, char &lt;span class="k"&gt;*&lt;/span&gt;argv[]&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;0&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E agora vamos implementar só a parte de ler do &lt;code&gt;stdin&lt;/code&gt; e escrever no &lt;code&gt;stdout&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// argc: número de argumentos&lt;/span&gt;
  &lt;span class="c1"&gt;// argc == 1 signfica que o programa foi chamado sem nenhum&lt;/span&gt;
  &lt;span class="c1"&gt;// argumento extra, exemplo: ./cat&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// lê um caracter do stdin&lt;/span&gt;
      &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// EOF significa fim do arquivo (end of file)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;EOF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="c1"&gt;// escreve o caracter no stdout&lt;/span&gt;
      &lt;span class="n"&gt;putc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O que esse programa faz é ficar lendo cara caractere do &lt;code&gt;stdin&lt;/code&gt; até o último do arquivo.&lt;/p&gt;

&lt;p&gt;Se a entrava for o teclado, ele lê até forçamos um &lt;code&gt;EOF&lt;/code&gt; apertando &lt;code&gt;ctrl&lt;/code&gt; + &lt;code&gt;D&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validando usando o &lt;code&gt;cat&lt;/code&gt; original
&lt;/h2&gt;

&lt;p&gt;Criei esse shell script para testar se o programa tem o mesmo comportamento do &lt;code&gt;cat&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# para cada arquivo na pasta home&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;f &lt;span class="k"&gt;in&lt;/span&gt; ~/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;

    &lt;span class="c"&gt;# executa o cat real, o meu cat e tira o md5 da saída&lt;/span&gt;
    &lt;span class="c"&gt;# &amp;lt; $f redireciona o conteúdo do arquivo atual para o stdin&lt;/span&gt;
    &lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &amp;lt; &lt;span class="nv"&gt;$f&lt;/span&gt; | &lt;span class="nb"&gt;md5sum&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;./cat &amp;lt; &lt;span class="nv"&gt;$f&lt;/span&gt; | &lt;span class="nb"&gt;md5sum&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;# se o md5 for diferente, é sinal que algo está errado&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;
    &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="s2"&gt; vs &lt;/span&gt;&lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
    &lt;span class="k"&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso não garante que nosso cat está totalmente correto, mas nos dá uma confiança maior de que está funcionando igual para muitos cenários.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementando o &lt;code&gt;cat&lt;/code&gt; com argumentos
&lt;/h2&gt;

&lt;p&gt;Caso sejam passados argumentos, o &lt;code&gt;cat&lt;/code&gt; vai tratá-los como nomes de arquivos, vai tentar ler um por um e escrever seu conteúdo no &lt;code&gt;stdout&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Obs.: o cat também recebe opcionalmente alguns outros argumentos, mas não vamos implementá-los aqui.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

      &lt;span class="c1"&gt;// abrimos o arquivo no modo leitura&lt;/span&gt;
      &lt;span class="kt"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;"r"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// lê um caracter do arquivo, printa no stdout&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;EOF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;putc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// fechamos o arquivo para evitar problemas&lt;/span&gt;
      &lt;span class="n"&gt;fclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tratando arquivos que não podem ser lidos
&lt;/h2&gt;

&lt;p&gt;Se você passar um arquivo que não existe ou que você não tem permissão para ler, vai acontecer um segmentation fault:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./cat naoexiste     
&lt;span class="o"&gt;[&lt;/span&gt;1]    99032 segmentation fault &lt;span class="o"&gt;(&lt;/span&gt;core dumped&lt;span class="o"&gt;)&lt;/span&gt;  ./cat naoexiste
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso acontece porque quando o arquivo não pode ser aberto, o &lt;code&gt;fopen&lt;/code&gt; retorna &lt;code&gt;NULL&lt;/code&gt; e altera a variável global &lt;code&gt;errno&lt;/code&gt; para o código do erro.&lt;br&gt;
Precisamos tratar esses erros antes de tentar fazer qualquer operação com o arquivo, senão teremos comportamentos indefinidos no nosso programa.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;errno.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// usamos a função strerror para printar uma&lt;/span&gt;
&lt;span class="c1"&gt;// mensagem de erro com base no errno&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// se tudo correr bem, esse valor não vai mudar,&lt;/span&gt;
  &lt;span class="c1"&gt;// e vamos retornar 0, que signifca ok&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;exit_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;"r"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// arquivo não existe / não pode ser lido&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// printar na saída de erro no mesmo formato que o cat, exemplo:&lt;/span&gt;
        &lt;span class="c1"&gt;// cat: naoexiste: No such file or directory&lt;/span&gt;
        &lt;span class="n"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"%s: %s: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;strerror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errno&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="c1"&gt;// se o arquivo não existe, o cat não encerra imediatamente,&lt;/span&gt;
        &lt;span class="c1"&gt;// mas continua lendo os próximos arquivos e só depois &lt;/span&gt;
        &lt;span class="c1"&gt;// finaliza com código de erro&lt;/span&gt;
        &lt;span class="n"&gt;exit_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errno&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// retornando o status&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;exit_status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Também seria necessário tratar erros de leitura e escrita em arquivos, mas vamos deixar para a parte 2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Código completo feito com &lt;code&gt;stdio.h&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;errno.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;exit_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;EOF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;putc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;"r"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"%s: %s: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;strerror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errno&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;exit_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errno&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;EOF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;putc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;exit_status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dúvidas comuns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Ler/escrever byte por byte não prejudica a performance?
&lt;/h3&gt;

&lt;p&gt;Não, porque os arquivos no C por padrão são “buferizados” (buffered), ou seja, quando você chama &lt;code&gt;putc&lt;/code&gt;, esse byte é escrito num array (&lt;em&gt;buffer&lt;/em&gt;) em memória até uma certa quantidade pré-definida, e depois esse array inteiro é escrito no arquivo de uma vez.&lt;/p&gt;

&lt;p&gt;Dessa forma a escrita se torna mais rápida, pois escrever na memória é ordens de vezes mais rápido que no disco.&lt;br&gt;
Essa escrita no arquivo de fato é chamada de “flush”, e você pode forçar um flush a qualquer momento no C usando &lt;code&gt;fflush&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Da mesma forma a leitura de um arquivo com &lt;code&gt;getc&lt;/code&gt; lê vários bytes e guarda num buffer em memória. Próximas chamadas para &lt;code&gt;getc&lt;/code&gt; vão ler desse buffer e não do disco, até que seja necessário consultar o disco de novo.&lt;/p&gt;

&lt;p&gt;Usei &lt;code&gt;getc&lt;/code&gt; e &lt;code&gt;putc&lt;/code&gt; como exemplos, mas o buffer é aplicado independente da função que você está usando para leitura ou escrita.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Bom, já falei bastante, apesar de não ter dado para abordar alguns assuntos.&lt;br&gt;
Espero que esse texto tenha sido útil e tenha te trazido insights sobre C, sobre o programa &lt;code&gt;cat&lt;/code&gt; e sobre como lidar com &lt;code&gt;stdin&lt;/code&gt;, &lt;code&gt;stdout&lt;/code&gt; e &lt;code&gt;stderr&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Na parte 2 eu pretendo reimplementar esse código de forma mais baixo nível, falando diretamente com o kernel, implementando manualmente os buffers de leitura e escrita e usando outra estratégia para tratar erros.&lt;/p&gt;

&lt;p&gt;Como sempre qualquer correção, sugestão ou informação que agregue é muito bem vinda. &lt;/p&gt;

&lt;p&gt;Até a próxima!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>braziliandevs</category>
      <category>c</category>
    </item>
    <item>
      <title>5 dicas simples para deixar seu site mais rápido</title>
      <dc:creator>Igor Melo</dc:creator>
      <pubDate>Sun, 16 Oct 2022 22:24:11 +0000</pubDate>
      <link>https://dev.to/igormelo/5-dicas-simples-para-deixar-seu-site-mais-rapido-m9</link>
      <guid>https://dev.to/igormelo/5-dicas-simples-para-deixar-seu-site-mais-rapido-m9</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Otimizar performance é parecido com economizar dinheiro.&lt;br&gt;
Não adianta você economizar centavos apagando as luzes da casa, enquanto usa ar condicionado horas por dia.&lt;/p&gt;

&lt;p&gt;Assim como economizar dinheiro, para otimizar performance é importante ter métricas para atacar a principal causa do problema, senão você vai estar jogando energia fora com algo que talvez não traga nenhum benefício perceptível.&lt;/p&gt;

&lt;p&gt;A métrica também é importante para confirmar que nossa alteração realmente melhorou a performance.&lt;/p&gt;

&lt;p&gt;No browser, você pode usar as diversas ferramentas que o DevTools oferece, como Performance, Performance Monitor, Memory, Network, etc, e também a extensão LightHouse.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tdTeoy2Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jaxzbq6f3dniv6n7mcqp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tdTeoy2Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jaxzbq6f3dniv6n7mcqp.png" alt="Ferramenta Performance do DevTools" width="800" height="569"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Você também pode usar outras ferramentas como Elastic APM e similares para monitorar tanto o front-end quanto o back-end.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f1eQ-gnr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/893ycdh1xc3n35yryesz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f1eQ-gnr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/893ycdh1xc3n35yryesz.png" alt="Elastic APM" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nesse artigo eu não vou me basear em métricas, porque na realidade vou dar sugestões de coisas que você pode experimentar para melhorar performance.&lt;/p&gt;

&lt;p&gt;A parte de medir e validar se houve melhoria de performance fica contigo.&lt;/p&gt;
&lt;h2&gt;
  
  
  1 - Use debounce e throttle
&lt;/h2&gt;

&lt;p&gt;Debounce e throttle são funções para atrasar ou limitar quantas vezes um processamento é realizado.&lt;br&gt;
O JavaScript não tem nativamente essas funções, porém você pode implementar ou usar uma biblioteca para isso.&lt;/p&gt;

&lt;p&gt;Nesse exemplo aqui eu botei um event listener no evento de &lt;code&gt;scroll&lt;/code&gt;.&lt;br&gt;
Eu fiz scroll por poucos segundos e esse listener foi disparado &lt;strong&gt;240 vezes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eUoi2Mpy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ch971ytnp716rzj2lixw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eUoi2Mpy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ch971ytnp716rzj2lixw.png" alt="window.onscroll = () =&amp;gt; console.log('scroll')" width="574" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se eu tiver alguma função que faz algum processamento pesado no meu event listener, eu vou travar a aba do navegador disparando esse processamento dezenas de vezes.&lt;/p&gt;
&lt;h3&gt;
  
  
  Debounce
&lt;/h3&gt;

&lt;p&gt;O &lt;code&gt;debounce&lt;/code&gt; atrasa a execução de uma função por um tempo determinado pelo usuário.&lt;br&gt;
Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onscroll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scrolled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;console.log&lt;/code&gt; só vai ser executado 1 segundo depois do &lt;strong&gt;último&lt;/strong&gt; evento de scroll.&lt;/p&gt;

&lt;h3&gt;
  
  
  Throttle
&lt;/h3&gt;

&lt;p&gt;O &lt;code&gt;throttle&lt;/code&gt; executa a chamada para a função num intervalo definido pelo usuário.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onscroll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;throttle&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scrolled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse caso, se o usuário ficar fazendo scroll, &lt;strong&gt;a cada segundo&lt;/strong&gt; vai ter um &lt;code&gt;console.log&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2 - Coloque só o crítico no &lt;code&gt;head&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Se você coloca todos os seus JS e CSS no &lt;code&gt;head&lt;/code&gt; do seu index.html, você está fazendo com que sua página fique &lt;strong&gt;em branco&lt;/strong&gt; até que &lt;strong&gt;todos&lt;/strong&gt; esses arquivos carreguem.&lt;/p&gt;

&lt;p&gt;Esse é o momento que vários usuários &lt;strong&gt;desistem de usar seu site&lt;/strong&gt;!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"pt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Meu site lento&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"estilo_critico.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"estilo_nao_critico1.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"estilo_nao_critico2.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script_nao_critico1.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script_nao_critico2.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- só vai aparecer depois que todos os arquvios forem baixados e processados --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Bem vindo!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uma regra simples é a seguinte:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;só coloque no &lt;code&gt;head&lt;/code&gt; o que você &lt;strong&gt;realmente&lt;/strong&gt; precisa que seja carregado e processado antes do browser mostrar algo na tela.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Só coloque estilos no &lt;code&gt;head&lt;/code&gt; que você considere críticos, exemplo: fontes, layout básico, cores.&lt;/p&gt;

&lt;p&gt;Só coloque scripts no &lt;code&gt;head&lt;/code&gt; se você realmente precisa que eles façam algo antes da página ser renderizada.&lt;/p&gt;

&lt;p&gt;Se você não precisa que um estilo ou script execute antes da página ser renderizada, coloque no fim do &lt;code&gt;body&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Resultado do html anterior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"pt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Meu site otimizado&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"estilo_critico.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- vai aparecer assim que o estilo_crítico.css carregar --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Bem vindo!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"estilo_nao_critico1.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"estilo_nao_critico2.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script_nao_critico1.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script_nao_critico2.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Obs.: no caso de scripts, você até pode deixá-los no &lt;code&gt;head&lt;/code&gt;, desde que use &lt;a href="https://www.w3schools.com/tags/att_script_defer.asp"&gt;defer&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Saiba mais:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Critical_rendering_path"&gt;Critical rendering path - Web performance | MDN&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3 - Coloque o crítico inline
&lt;/h2&gt;

&lt;p&gt;Fazer uma requisição HTTP é algo que pode ser bem lento, principalmente em redes móveis, porque o tempo da requisição chegar no servidor e voltar é muito grande.&lt;/p&gt;

&lt;p&gt;Dessa forma, no primeiro carregamento da sua página você deve buscar fornecer o crítico num único arquivo HTML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"pt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Meu site rapidão&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;/* meu estilo crítico */&lt;/span&gt;
    &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- vai aparecer mais rápido pois não vai fazer uma req. pro estilo crítico --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Bem vindo!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"estilo_nao_critico1.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"estilo_nao_critico2.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script_nao_critico1.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script_nao_critico2.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Um site que faz isso bem é o G1:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5zrHV1kZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k0qlpiqxa17tsbv3zw7c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5zrHV1kZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k0qlpiqxa17tsbv3zw7c.png" alt="G1 parcialmente carregado" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mesmo desativando o cache e simulando um 3G lento, em &lt;strong&gt;menos de 2 segundos&lt;/strong&gt; o texto da notícia e o layout básico da página foi carregado, o que para um usuário é bem aceitável. &lt;/p&gt;

&lt;p&gt;Já o Github é outra história: &lt;/p&gt;

&lt;p&gt;O site carrega &lt;strong&gt;8 estilos&lt;/strong&gt; no &lt;code&gt;head&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lzK10BsZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g4oqruvnpizgcvn1k4m7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lzK10BsZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g4oqruvnpizgcvn1k4m7.png" alt="First Contentful Paint do Github" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O navegador levou &lt;strong&gt;19 segundos&lt;/strong&gt; para mostrar algo na tela! Muitos usuários desistiriam no caminho. &lt;/p&gt;

&lt;p&gt;Também é preciso ter um cuidado especial com single page applications, pois elas são todas renderizadas no cliente, e muitas vezes acabam fazendo muitas requisições.&lt;br&gt;
Você pode experimentar reduzir o número de requisições usando GraphQL ou outras técnicas como server side rendering.&lt;/p&gt;

&lt;p&gt;Saiba mais:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imkev.dev/inlining-critical-css"&gt;Inlining critical CSS&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  4 - Use cache de requisições HTTP
&lt;/h2&gt;

&lt;p&gt;Caching é uma ótima estratégia para diminuir tempo de carregamento de páginas e entregar uma experiência instantânea para o usuário.&lt;/p&gt;
&lt;h3&gt;
  
  
  4.1 - &lt;code&gt;Cache-Control&lt;/code&gt; e &lt;code&gt;max-age&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;O &lt;code&gt;cache-control&lt;/code&gt; é um header de resposta HTTP que, entre outras coisas, diz para o navegador por quanto tempo ele pode salvar o resultado de uma requisição para usar no futuro.&lt;/p&gt;

&lt;p&gt;Esse tempo é definido pelo &lt;code&gt;max-age&lt;/code&gt;, que é um valor sempre em segundos.&lt;/p&gt;

&lt;p&gt;Exemplo: cache de dois minutos&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cache-Control: max-age=120
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se eu fizer umas requisições com o mesmo path, exemplo &lt;code&gt;/img/1234.png&lt;/code&gt;, a primeira vai trazer do back-end e a salvar em cache por 2 minutos.&lt;/p&gt;

&lt;p&gt;Se na segunda vez ainda não tiver passado 2 os minutos, o resultado da requisição anterior vai ser reutilizado, sem nem precisar falar com o back-end.&lt;/p&gt;

&lt;p&gt;Isso traz um benefício de performance enorme, porque trazer do disco pode ser milhares de vezes mais rápido do que trazer do servidor.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2 - ETag
&lt;/h3&gt;

&lt;p&gt;ETag é um outro header de resposta que também serve como validação de cache.&lt;br&gt;
O ETag é pensado para ser um código curto identificador daquela resposta.&lt;/p&gt;

&lt;p&gt;Em resumo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;respostas idênticas devem ter o mesmo ETag&lt;/li&gt;
&lt;li&gt;respostas distintas devem ter ETags diferentes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O motivo disso é que quando o navegador fizer uma requisição que responda com um ETag, ele vai salvar a resposta no disco e nas próximas vezes ele vai enviar o ETag para o servidor, falando "Se o body mudar, me retorna o novo body. Se não, me retorne um status 304 (Not Modified) sem body.".&lt;/p&gt;

&lt;p&gt;ETags podem ser implementadas no lado do servidor fazendo hash do body da resposta.&lt;/p&gt;

&lt;p&gt;Se for uma requisição para um arquivo, pode ser baseada no momento de última modificação.&lt;/p&gt;

&lt;p&gt;Se for uma requisição que consulta dados do banco, também pode usar a última vez que um dado foi alterado...&lt;br&gt;
Use sua imaginação.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3 - Combinando &lt;code&gt;max-age&lt;/code&gt; com &lt;code&gt;ETag&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Quem disse que você precisa escolher um ou outro?&lt;br&gt;
Você pode perfeitamente pôr um cache de 5 minutos numa imagem, e também usar uma ETag.&lt;/p&gt;

&lt;p&gt;Quando o cache expirar, o navegador vai fazer uma requisição checando se a ETag mudou, e se não, vai manter o dado que ele já tem em cache por mais 5 minutos.&lt;/p&gt;

&lt;p&gt;Saiba mais:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control"&gt;Cache-Control - HTTP | MDN&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag"&gt;ETag - HTTP | MDN&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5 - Mostre menos coisa na tela de uma vez
&lt;/h2&gt;

&lt;p&gt;Mais elementos na tela significa mais coisa em memória, mais elementos para recalcular o estilo e layout, mais event listeners, mais trabalho para a GPU, etc…&lt;/p&gt;

&lt;p&gt;Se tiver muitas imagens, coloque lazy loading, porque carregar muitas imagens em paralelo vão dar uma sensação de maior lentidão e pode até travar o seu site.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WgUKK-gj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/auzljrxxgatw591ipkt3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WgUKK-gj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/auzljrxxgatw591ipkt3.png" alt="Lazy loading de imagens" width="600" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use paginação e/ou infinite scroll para controlar a quantidade de conteúdo na tela.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NlWs7gDN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p6rtxcmbt2uz9237zhq5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NlWs7gDN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p6rtxcmbt2uz9237zhq5.png" alt="Paginação" width="561" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nD29PYKM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x69vhwqoyu0xhfbwprox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nD29PYKM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x69vhwqoyu0xhfbwprox.png" alt="Infinite scroll" width="573" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dessa forma o usuário não precisa carregar megabytes de dados de uma vez só para ver o início do conteúdo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Como o título avisou, foram dicas bem simples, porém que eu considero bem úteis e eficazes no desafio de entregar boa performance.&lt;/p&gt;

&lt;p&gt;Eu tenho vontade de falar sobre outros assuntos mais desafiadores, como memory leaks, repaint and reflow, e estou lendo o livro &lt;a href="https://www.amazon.com.br/High-Performance-Browser-Networking-Developer/dp/1449344763/ref=sr_1_1?qid=1665932719&amp;amp;refinements=p_27%3AIlya+Grigorik&amp;amp;s=books&amp;amp;sr=1-1&amp;amp;ufe=app_do%3Aamzn1.fos.6a09f7ec-d911-4889-ad70-de8dd83c8a74"&gt;High Performance Browser Networking do Ilya Grigorik&lt;/a&gt; para transformar numa série de artigos também.&lt;/p&gt;

&lt;p&gt;Por hoje é só. Aguardo seu feedback!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
      <category>tutorial</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Golang: Desmistificando channels - Select</title>
      <dc:creator>Igor Melo</dc:creator>
      <pubDate>Wed, 12 Oct 2022 19:51:59 +0000</pubDate>
      <link>https://dev.to/igormelo/golang-desmistificando-channels-select-2ncp</link>
      <guid>https://dev.to/igormelo/golang-desmistificando-channels-select-2ncp</guid>
      <description>&lt;h2&gt;
  
  
  Select: selecionando o canal “mais rápido”
&lt;/h2&gt;

&lt;h3&gt;
  
  
  O desafio
&lt;/h3&gt;

&lt;p&gt;Imagina que você quer consultar as informações de um local a partir de um CEP.&lt;/p&gt;

&lt;p&gt;Existem algumas APIs de CEP, mas você quer que o resultado seja o mais rápido possível. O que você faz?&lt;/p&gt;

&lt;p&gt;Você poderia fazer um benchmark para ver qual é a API mais rápida, mas isso não seria muito preciso, porque uma certa API pode ficar mais lenta em certos horários, ou pode ser mais rápida para alguns CEPs e não para outros...&lt;/p&gt;

&lt;p&gt;Uma estratégia que podemos usar é disparar uma requisição para cada uma e usar a primeira que responder com um status de &lt;code&gt;200 OK&lt;/code&gt;, e essa é justamente a ideia do &lt;a href="https://github.com/BrasilAPI/cep-promise" rel="noopener noreferrer"&gt;projeto CEP Promise do BrasilAPI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F27ku1wsh4kbmuuqsal4i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F27ku1wsh4kbmuuqsal4i.png" alt="CEP Promise"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dessa forma não só ganhamos em performance como também em disponibilidade, porque mesmo se uma API falhar, ainda vamos ter outra(s) de fallback.&lt;/p&gt;

&lt;p&gt;Para implementar algo parecido, podemos usar o &lt;code&gt;select&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O select é como se fosse um &lt;code&gt;switch&lt;/code&gt;, onde cada &lt;code&gt;case&lt;/code&gt; é uma tentativa de comunicar com um canal.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;primeiro&lt;/strong&gt; &lt;code&gt;case&lt;/code&gt; com um recebimento ou envio pronto para ser executado vai ser o case que a goroutine vai entrar. &lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;After&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1 segundo"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;After&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"500ms"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// "500ms"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;select&lt;/code&gt; por padrão pausa a execução da goroutine. Um &lt;code&gt;select&lt;/code&gt; sem &lt;code&gt;case&lt;/code&gt; vai parar a goroutine indefinidamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="c"&gt;// Se não tiver outra goroutine, vai causar um deadlock e encerrar&lt;/span&gt;
    &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;select&lt;/code&gt;, assim como o &lt;code&gt;switch&lt;/code&gt;, também tem um caso &lt;code&gt;default&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Ele cai no &lt;code&gt;default&lt;/code&gt; quando nenhum dos outros casos está pronto para ser executado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;

&lt;span class="c"&gt;// combinando um loop com um select&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"li do channel:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"channel ainda não está preparado para leitura"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// "channel ainda não está preparado para leitura"&lt;/span&gt;
&lt;span class="c"&gt;// "channel ainda não está preparado para leitura"&lt;/span&gt;
&lt;span class="c"&gt;// "li do channel: 123"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No exemplo de consulta de CEP, um código fictício para pegar o primeiro CEP que retornar seria:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;cep&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"12345678"&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="n"&gt;CepInfo&lt;/span&gt;

&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;cepInfoCorreios&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Correios retornou primeiro"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;cepInfoViaCep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ViaCEP retornou primeiro"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// obs.: num caso real você teria que cancelar as requisições HTTP também&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Golang: Desmistificando channels - Buffered Channels</title>
      <dc:creator>Igor Melo</dc:creator>
      <pubDate>Sat, 01 Oct 2022 21:22:43 +0000</pubDate>
      <link>https://dev.to/igormelo/golang-desmistificando-channels-buffered-channels-16d0</link>
      <guid>https://dev.to/igormelo/golang-desmistificando-channels-buffered-channels-16d0</guid>
      <description>&lt;h2&gt;
  
  
  Buffered channels
&lt;/h2&gt;

&lt;p&gt;Se você já conseguiu entender e praticar bem a parte de channels, podemos falar sobre buffered channels.&lt;/p&gt;

&lt;p&gt;Buffered channels são channels que não bloqueiam o envio e recebimento em alguns cenários, porque eles guardam os valores enviados temporariamente num buffer, que vai ser lido e removido do buffer quando alguém receber.&lt;/p&gt;

&lt;p&gt;Você cria um buffered channel com o tamanho do buffer que você quer, por exemplo 5, daí você vai poder fazer 5 envios sem bloquear a goroutine.&lt;/p&gt;

&lt;p&gt;A partir daí, enquanto o buffer estiver cheio, os próximos envios vão bloquear, da mesma forma que num channel sem buffer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// basta passar um tamanho na hora de criar o channel&lt;/span&gt;
&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// não vão bloquear a gourotine&lt;/span&gt;
&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"A"&lt;/span&gt;
&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"B"&lt;/span&gt;
&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;

&lt;span class="c"&gt;// buffer cheio, novos envios vão bloquear a goroutine &lt;/span&gt;
&lt;span class="c"&gt;// até que surja um  espaço livre no buffer&lt;/span&gt;
&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"D"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Da mesma forma, receber de um buffered channel não vai bloquear se o buffer não estiver vazio.&lt;/p&gt;

&lt;p&gt;Se ele estiver vazio, vai funcionar como um channel sem buffer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// não vão bloquear a gourotine&lt;/span&gt;
&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"A"&lt;/span&gt;
&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"B"&lt;/span&gt;
&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;

&lt;span class="c"&gt;// não vão bloquear a goroutine&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="c"&gt;// "A"&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="c"&gt;// "B"&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="c"&gt;// "C"&lt;/span&gt;

&lt;span class="c"&gt;// buffer vazio, vai bloquear a goroutine até um novo envio&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usando buffered channels para controlar número de goroutines
&lt;/h2&gt;

&lt;p&gt;Uma grande vantagem dos buffered channels é que eles passam a bloquear quando o buffer está cheio, e podemos usar isso ao nosso favor.&lt;/p&gt;

&lt;p&gt;Nesse exemplo aqui eu tenho um programa que vai ficar criando goroutines indeterminadamente e cada goroutine faz uma requisição GET.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

            &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.google.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O problema é que não podemos ficar criando goroutines e clientes HTTP sem limites, porque memória não é infinita, e nem vai ser muito eficiente fazer milhares de requisições ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;Esse programa vai cedo ou tarde dar um erro e vai encerrar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"runtime error: invalid memory address or nil pointer dereference"

Stack:
    4  0x0000000000744764 in main.main.func1
        at /home/igor/Git/pessoal/got/main.go:21
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para resolver isso, vamos criar um buffered channel antes do loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// o tipo não importa muito, porque não estamos interessados no valor enviado&lt;/span&gt;
&lt;span class="c"&gt;// nesse caso vou limitar para 50 goroutines fazendo requisições&lt;/span&gt;
&lt;span class="n"&gt;limitter&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Toda vez antes de criar uma goroutine vamos adicionar um valor ao buffer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;limitter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Toda vez que a goroutine finalizar, vamos tirar um valor do buffer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;limitter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;limitter&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O resultado vai ser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

            &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.google.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;
        &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Golang: Desmistificando channels - Range e close</title>
      <dc:creator>Igor Melo</dc:creator>
      <pubDate>Sat, 01 Oct 2022 21:21:30 +0000</pubDate>
      <link>https://dev.to/igormelo/golang-desmistificando-channels-range-e-close-1nm5</link>
      <guid>https://dev.to/igormelo/golang-desmistificando-channels-range-e-close-1nm5</guid>
      <description>&lt;h2&gt;
  
  
  Usando range e close
&lt;/h2&gt;

&lt;p&gt;Se você tiver um canal, você pode receber mensagens usando um &lt;code&gt;for range&lt;/code&gt;, parecido com percorrer um array ou slice.&lt;/p&gt;

&lt;p&gt;Só que a diferença é que um for range em um canal vai receber valores até o canal ser fechado. Se o canal nunca for fechado, o loop vai ficar bloqueado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// essa linha nunca é executada, porque val nunca é recebido&lt;/span&gt;
  &lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para fechar um canal é muito simples, porém deve ser feito com cuidado, porque se você fechar um canal e tentar enviar isso vai causar um &lt;code&gt;panic&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Então tem duas regras básicas que você pode seguir para fechar um canal:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Você deve fechar na função que envia, porque só ela sabe quando pode fechar&lt;/li&gt;
&lt;li&gt;Você deve garantir que está fechando depois de todas as goroutines terem terminado de enviar&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Não tem problema tentar ler de um channel fechado em um range:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// não vai entrar aqui porque não tem nada para ser lido e não vai&lt;/span&gt;
    &lt;span class="c"&gt;// repetir porque o channel está fechado&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Você pode seguramente fechar um channel depois de ter enviado todos os valores:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c"&gt;// neste caso eu estou usando WaitGroup pra garantir que todas as&lt;/span&gt;
    &lt;span class="c"&gt;// goroutines já escreveram no channel antes de poder fechá-lo&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c"&gt;// faço um processamento concorrente de values&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;
        &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fazendo múltiplas goroutines esperarem por um sinal
&lt;/h2&gt;

&lt;p&gt;Uma coisa que você pode querer fazer é notificar uma goroutine que ela pode começar a fazer algum tipo de processamento.&lt;br&gt;
Isso é bem fácil... Basta usar um channel e enviar um valor. Quando ela receber é porque ela pode iniciar.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// esse channel serve para saber se o nosso servidor está pronto ou não&lt;/span&gt;
    &lt;span class="n"&gt;ready&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;startHttpServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;ready&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="c"&gt;// fazer coisas que não dependam do servidor rodando&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;

    &lt;span class="c"&gt;// esperar o servidor iniciar&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ready&lt;/span&gt;

    &lt;span class="c"&gt;// fazer uma requisição para o servidor, agora que podemos garantir que ele está rodando&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:3000/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso até funciona se tivermos só uma goroutine esperando o servidor iniciar.&lt;/p&gt;

&lt;p&gt;Mas e se quisermos ter várias esperando esse sinal, como resolver isso?&lt;br&gt;
Enviar um valor ao channel para cada uma não é uma solução viável.&lt;/p&gt;

&lt;p&gt;Para isso podemos fazer um truque esperto que é usar o close do channel.&lt;/p&gt;

&lt;p&gt;Em vez de enviarmos um valor para o channel para notificar que o servidor iniciou, podemos simplesmente fechar o channel e todas as goroutines que estiverem bloqueadas tentando receber do channel vão ser desbloqueadas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ready&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;startHttpServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// usando close em vez de enviar&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="c"&gt;// esperar o servidor iniciar&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ready&lt;/span&gt;

    &lt;span class="c"&gt;// fazer uma requisição para o servidor, agora que podemos garantir que ele está rodando&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:3000/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>go</category>
      <category>braziliandevs</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Golang: Desmistificando channels - Exemplo concreto</title>
      <dc:creator>Igor Melo</dc:creator>
      <pubDate>Sat, 01 Oct 2022 21:17:00 +0000</pubDate>
      <link>https://dev.to/igormelo/golang-desmistificando-channels-2pkk</link>
      <guid>https://dev.to/igormelo/golang-desmistificando-channels-2pkk</guid>
      <description>&lt;h2&gt;
  
  
  Exemplo concreto de uso de channels
&lt;/h2&gt;

&lt;p&gt;Vamos supor que você tenha um slice de URLs de arquivos e queira baixar todos de forma simultânea.&lt;/p&gt;

&lt;p&gt;Você pode começar implementando uma solução sequencial, e depois fazer isso concorrente com goroutines, e por último usar os channels para esperar cada download terminar e comunicar que eles finalizaram.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fazendo os downloads de forma sequencial
&lt;/h3&gt;

&lt;p&gt;Digamos que você tenha um slice com os arquivos que quer baixar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"http://files.com/file1.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"http://files.com/file2.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"http://files.com/file3.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para fazer o download deles, você pode criar uma função &lt;code&gt;download&lt;/code&gt; que recebe a URL do arquivo e faz o download.&lt;/p&gt;

&lt;p&gt;Para simular o download, vamos fazer uma função que espera um tempo aleatório entre 0 e 3 segundos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, vamos fazer o download de cada arquivo de forma sequencial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"concluído:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O resultado vai ser esse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;concluído: http://files.com/file1.png
concluído: http://files.com/file2.png
concluído: http://files.com/file3.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No pior cenário o programa vai levar 3 segundos por download, ou seja, um total de 9 segundos.&lt;/p&gt;

&lt;p&gt;Se conseguirmos fazer isso de forma simultânea, o pior cenário vai levar 3 segundos no total.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usando goroutines para fazer downloads concorrentes
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Criamos um channel de string
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Poderia ser de outro tipo, mas nesse caso vou mandar a URL do download que finalizou, por isso vou usar um &lt;code&gt;chan string&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Iniciar o download numa nova goroutine
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso não vai funcionar, porque a goroutine &lt;code&gt;main&lt;/code&gt; vai finalizar primeiro e vai encerrar o programa.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Quando o download finalizar, vamos enviar para o channel a URL
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;downloadAndNotify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// agora em vez de só baixar em outra goroutine, estamos&lt;/span&gt;
    &lt;span class="c"&gt;// enviando a url do download finalizado para o channel&lt;/span&gt;
    &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;downloadAndNotify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// obs.: o programa vai continuar encerrando antes de fazer os downloads&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Recebemos os valores do channel
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;downloadAndNotify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// sabemos que o números de resultados vai ser igual ao &lt;/span&gt;
    &lt;span class="c"&gt;// tamanho de urls, então podemos fazer esse for para repetir len(urls) vezes&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="c"&gt;// recebemos um resultado do channel&lt;/span&gt;
        &lt;span class="c"&gt;// lembre-se, esse receber vai bloquear até que alguma goroutine envie algo&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;

        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"concluído:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// como o loop anterior repete 3x, todos os resultados das 3 goroutines&lt;/span&gt;
    &lt;span class="c"&gt;// são lidos, e a main finaliza quando todos os downloads terminam&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;concluído: http://files.com/file2.png
concluído: http://files.com/file1.png
concluído: http://files.com/file3.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos também usar uma função anônima no lugar do &lt;code&gt;downloadAndNotify&lt;/code&gt;, e o código completo ficaria assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"math/rand"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"http://files.com/file1.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"http://files.com/file2.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"http://files.com/file3.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// isso é necessário agora porque estamos usando uma closure&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;

        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;
        &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"concluído:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>programming</category>
      <category>go</category>
      <category>tutorial</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Golang: Desmistificando channels - Conceito e sintaxe</title>
      <dc:creator>Igor Melo</dc:creator>
      <pubDate>Sat, 01 Oct 2022 21:14:37 +0000</pubDate>
      <link>https://dev.to/igormelo/golang-desmistificando-channels-4n7h</link>
      <guid>https://dev.to/igormelo/golang-desmistificando-channels-4n7h</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Resolvi fazer esse texto porque no meu primeiro contato com channels eu não entendi muito bem como funcionava, daí eu sempre fugia para o &lt;code&gt;WaitGroup&lt;/code&gt; ou fazia alguma &lt;code&gt;Mutex&lt;/code&gt; para usar goroutines, mesmo quando a melhor solução seria usar channels.&lt;/p&gt;

&lt;p&gt;Fiz esse texto com o objetivo de deixar mais claro como usar channels e os problemas comuns que você vai encontrar ao usá-los de forma errada.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é e para que serve?
&lt;/h2&gt;

&lt;p&gt;Channel, ou canal, é uma forma nativa do Go para comunicar e sincronizar goroutines.&lt;/p&gt;

&lt;p&gt;O channel já é &lt;em&gt;thread-safe&lt;/em&gt; por padrão, ou seja, enviar e receber são operações seguras de se usar com goroutines, então você não vai precisar se preocupar em criar &lt;em&gt;mutexes&lt;/em&gt; nem nada do tipo.&lt;/p&gt;

&lt;p&gt;Com channels você consegue facilmente fazer coisas como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coletar o resultado de várias goroutines fazendo requisições HTTP e ir mostrando na tela&lt;/li&gt;
&lt;li&gt;Criar workers que processam no máximo 50 operações concorrentes&lt;/li&gt;
&lt;li&gt;Fazer outras goroutines esperarem por um sinal que sua aplicação iniciou&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Criando e usando channels
&lt;/h2&gt;

&lt;p&gt;Para criar um channel, fazemos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O channel pode ser basicamente de qualquer tipo: &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;struct{}&lt;/code&gt; e outros. &lt;/p&gt;

&lt;p&gt;Esse tipo é o tipo de dado que vai ser enviado e recebido pelo canal.&lt;br&gt;
Detalhe que ao enviar uma informação para um channel, o que o outro lado recebe é uma cópia do dado.&lt;/p&gt;

&lt;p&gt;Dessa forma você já evita vários problemas de data race, porque a goroutine que recebeu o dado pode ler e modificar sem o risco de afetar outra goroutine.&lt;br&gt;
A exceção para isso é quando você cria channels de tipos que não copiam o dado inteiro, como ponteiros, maps e slices.&lt;/p&gt;

&lt;p&gt;Exemplos de channels que vão copiar somente a referência, e não o dado completo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para enviar informações para um channel, fazemos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"Shakespeare"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para receber do channel, fazemos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;ch&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chan&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// recebendo de um channel e descartando valor&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt;

    &lt;span class="c1"&gt;// recebendo de um channel e guardando numa variável&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;ch&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Por que não funciona?
&lt;/h2&gt;

&lt;p&gt;Se você rodar qualquer um dos códigos do exemplo anterior, vai acontecer isso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;fatal error: all goroutines are asleep - deadlock!

goroutine 1 &lt;span class="o"&gt;[&lt;/span&gt;chan send]:
main.main&lt;span class="o"&gt;()&lt;/span&gt;
        main.go:5 +0x31
&lt;span class="nb"&gt;exit &lt;/span&gt;status 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso acontece porque os channels por padrão vão pausar a execução da goroutine que tentar enviar ou receber. Ou seja, a goroutine que tentar enviar vai esperar até que outra esteja pronta para receber, e da mesma forma a goroutine que tentar receber vai esperar até que outra envie. &lt;/p&gt;

&lt;p&gt;No caso acima quando eu tento enviar para um channel, eu pauso a goroutine &lt;code&gt;main&lt;/code&gt; para esperar que outra goroutine leia o que enviei, mas como não tem outra goroutine rodando, a &lt;code&gt;main&lt;/code&gt; vai ficar esperando “para sempre” (&lt;code&gt;deadlock&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;O runtime do Go percebe que esse programa vai ficar parado indeterminadamente, porque todas as goroutines estão “dormindo” (&lt;code&gt;all goroutines are asleep&lt;/code&gt;), então ele encerra o programa com um código de erro.&lt;/p&gt;

&lt;p&gt;O mesmo acontece no segundo exemplo.&lt;/p&gt;

&lt;p&gt;Também existem os &lt;em&gt;buffered channels&lt;/em&gt;, que permitem a gente enviar para um canal uma quantidade X de dados antes que ele comece a bloquear a goroutine, mas vamos ver isso mais para frente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usando channels corretamente
&lt;/h2&gt;

&lt;p&gt;Para corrigir o problema do deadlock anterior, vamos criar outra goroutine que lê do channel, enquanto a goroutine &lt;code&gt;main&lt;/code&gt; vai enviar para o channel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// obs. 1: 'go' vai fazer com que essa função seja executada numa &lt;/span&gt;
    &lt;span class="c"&gt;// nova goroutine, então ler do channel não vai bloquear a main&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// obs. 2: eu não preciso passar o ch como parâmetro da função&lt;/span&gt;
        &lt;span class="c"&gt;// porque o ch está no da main escopo&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="c"&gt;// a goroutine main vai esperar até que consiga enviar&lt;/span&gt;
    &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fim"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se você está confuso com &lt;code&gt;ch &amp;lt;- 12&lt;/code&gt; e &lt;code&gt;&amp;lt;-ch&lt;/code&gt;, você pode pensar que a seta aponta para onde o dado está fluindo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// o dado está saindo do channel ch (receber) e sendo descartado&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;

&lt;span class="c"&gt;// o dado está saindo do channel ch (receber) e sendo atribuído à variável x&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;

&lt;span class="c"&gt;// o dado 12 está indo para o channel ch (enviar)&lt;/span&gt;
&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Isso conclui a parte 1 dessa série, com o conceito básico de channels.&lt;br&gt;
Na parte 2 vamos ver um exemplo mais realístico de onde e como seria utilizado channels.&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>go</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
