<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.1.1">Jekyll</generator><link href="http://hardfloat.es//feed.xml" rel="self" type="application/atom+xml" /><link href="http://hardfloat.es//" rel="alternate" type="text/html" /><updated>2026-05-06T05:16:41-05:00</updated><id>http://hardfloat.es//feed.xml</id><title type="html">Hardfloat</title><subtitle>Blog sobre informática y sistemas embebidos</subtitle><author><name>Andres</name></author><entry><title type="html">Go coverage</title><link href="http://hardfloat.es//blog/2024/12/18/go-coverage.html" rel="alternate" type="text/html" title="Go coverage" /><published>2024-12-18T00:00:00-06:00</published><updated>2024-12-18T00:00:00-06:00</updated><id>http://hardfloat.es//blog/2024/12/18/go-coverage</id><content type="html" xml:base="http://hardfloat.es//blog/2024/12/18/go-coverage.html"><![CDATA[<ul id="markdown-toc">
  <li><a href="#introducción" id="markdown-toc-introducción">Introducción</a>    <ul>
      <li><a href="#1-medir-cobertura-básica-de-paquetes" id="markdown-toc-1-medir-cobertura-básica-de-paquetes">1. Medir cobertura básica de paquetes</a></li>
      <li><a href="#2-analizar-funciones" id="markdown-toc-2-analizar-funciones">2. Analizar funciones</a></li>
      <li><a href="#3-generar-html" id="markdown-toc-3-generar-html">3. Generar HTML</a></li>
    </ul>
  </li>
</ul>

<h1 id="introducción">Introducción</h1>

<p>El <strong>code coverage</strong> (cobertura de código) es una métrica que indica qué
porcentaje de tu código es ejecutado durante los tests. Go también tiene
herramientas integradas para calcular la cobertura.</p>

<h2 id="1-medir-cobertura-básica-de-paquetes">1. Medir cobertura básica de paquetes</h2>

<p>El comando:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go <span class="nb">test</span> <span class="nt">-cover</span>
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ok  	tailscale.com/appc	0.012s	coverage: 83.5% of statements
ok  	tailscale.com/atomicfile	0.005s	coverage: 14.3% of statements
ok  	tailscale.com/chirp	0.508s	coverage: 78.0% of statements
</code></pre></div></div>

<p>Ejecuta todas las pruebas en el proyecto y muestra un porcentaje de cobertura
para cada paquete.</p>

<h2 id="2-analizar-funciones">2. Analizar funciones</h2>

<p>Para mostrar un análisis basado en funciones:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go <span class="nb">test</span> <span class="nt">-coverprofile</span><span class="o">=</span>cov.out <span class="o">&amp;&amp;</span> go tool cover <span class="nt">-func</span><span class="o">=</span>cov.out
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tailscale.com/envknob/envknob.go:175:   RegisterDuration 0.0%
tailscale.com/envknob/envknob.go:194:	RegisterInt	0.0%
tailscale.com/envknob/envknob.go:211:	setBoolLocked 50.0%
tailscale.com/envknob/envknob.go:225:	setOptBoolLocked 50.0%
tailscale.com/envknob/envknob.go:239:	setDurationLocked 0.0%
tailscale.com/envknob/envknob.go:253:	setIntLocked 0.0%
tailscale.com/envknob/envknob.go:269:	Bool 100.0%
tailscale.com/envknob/envknob.go:275:	BoolDefaultTrue 0.0%
tailscale.com/envknob/envknob.go:279:	boolOr 40.0%
</code></pre></div></div>

<h2 id="3-generar-html">3. Generar HTML</h2>

<p>También es posible generar un documento HTML que muestra en verde las líneas de
código que están cubiertas y en rojo, las líneas que no se han probado.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go <span class="nb">test</span> <span class="nt">-coverprofile</span><span class="o">=</span>cov.out <span class="o">&amp;&amp;</span> go tool cover <span class="nt">-html</span><span class="o">=</span>cov.out
</code></pre></div></div>]]></content><author><name>Andres</name></author><category term="Go" /><category term="Desarrollo" /><category term="dev" /><category term="coverage" /></entry><entry><title type="html">Go profiling con pprof</title><link href="http://hardfloat.es//blog/2024/12/11/go-profiling.html" rel="alternate" type="text/html" title="Go profiling con pprof" /><published>2024-12-11T00:00:00-06:00</published><updated>2024-12-11T00:00:00-06:00</updated><id>http://hardfloat.es//blog/2024/12/11/go-profiling</id><content type="html" xml:base="http://hardfloat.es//blog/2024/12/11/go-profiling.html"><![CDATA[<ul id="markdown-toc">
  <li><a href="#introducción" id="markdown-toc-introducción">Introducción</a></li>
  <li><a href="#con-tests" id="markdown-toc-con-tests">Con tests</a></li>
  <li><a href="#en-runtime" id="markdown-toc-en-runtime">En runtime</a></li>
  <li><a href="#links" id="markdown-toc-links">Links</a></li>
</ul>

<h2 id="introducción">Introducción</h2>

<p>Go posee herramientas para hacer profiling de manera sencilla. Cuando hacemos
profiling tratamos de identificar las partes del código que más se demora. Para
ello debemos de recopilar datos como tiempos de ejecución, uso de memoria,
llamadas de funciones, etc.</p>

<p>En Go, esta herramienta se llama <a href="https://pkg.go.dev/runtime/pprof">pprof</a>. El
enlace anterior se muestran distintas formas de usar esta herramienta, pero en
este artículo veremos las dos más comunes:</p>

<ul>
  <li>Con tests</li>
  <li>En runtime</li>
</ul>

<h2 id="con-tests">Con tests</h2>

<p>Si tenemos tests y conocemos el caso de prueba que ejercita la parte de código
que vamos a analizar, tan solo tenemos que agregar el flag <em>-cpuprofile</em>.</p>

<p>Pongamos este ejemplo sencillo:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"math"</span>
	<span class="s">"testing"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">compute</span><span class="p">(</span><span class="n">n</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
	<span class="n">quickComputation</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
	<span class="n">moderateComputation</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
	<span class="n">heavyComputation</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">TestComputation</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
	<span class="n">compute</span><span class="p">(</span><span class="m">100</span><span class="n">_000_000</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">heavyComputation</span><span class="p">(</span><span class="n">n</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">float64</span> <span class="p">{</span>
	<span class="n">result</span> <span class="o">:=</span> <span class="m">0.0</span>
	<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
		<span class="n">result</span> <span class="o">+=</span> <span class="n">math</span><span class="o">.</span><span class="n">Sqrt</span><span class="p">(</span><span class="kt">float64</span><span class="p">(</span><span class="n">i</span><span class="p">))</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">result</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">moderateComputation</span><span class="p">(</span><span class="n">n</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
	<span class="n">sum</span> <span class="o">:=</span> <span class="m">0</span>
	<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
		<span class="n">sum</span> <span class="o">+=</span> <span class="n">i</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">sum</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">quickComputation</span><span class="p">(</span><span class="n">n</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
	<span class="k">return</span> <span class="n">n</span> <span class="o">*</span> <span class="p">(</span><span class="n">n</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span> <span class="o">/</span> <span class="m">2</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Lo esperable es que la función que más tiempo de CPU consuma sea
<em>heavyComputation</em>. Veamos que dice pprof:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Corre el tests y guarda los datos del profile en cpu.prof</span>
go <span class="nb">test</span> <span class="nt">-cpuprofile</span><span class="o">=</span>cpu.prof <span class="nb">.</span>
<span class="c"># Leemos cpu.prof</span>
go tool pprof cpu.prof
</code></pre></div></div>
<p>Luego de lanzar el último comando se abre una terminal. Si escribimos <em>top</em> nos muestra el top de funciones que más CPU consumen ordenadas de mayor a menor:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>File: profiling.test
Type: cpu
Time: Dec 9, 2024 at 3:01pm (WET)
Duration: 201.10ms, Total samples = 70ms (34.81%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 70ms, 100% of 70ms total
      flat  flat%   sum%        cum   cum%
      40ms 57.14% 57.14%       40ms 57.14%  profiling.heavyComputation (inline)
      30ms 42.86%   100%       30ms 42.86%  profiling.moderateComputation (inline)
         0     0%   100%       70ms   100%  profiling.TestComputation
         0     0%   100%       70ms   100%  profiling.compute (inline)
         0     0%   100%       70ms   100%  testing.tRunner
(pprof) 
</code></pre></div></div>

<p>Como vemos nos muestra <em>heavyComputation</em> en el primer puesto.</p>

<p>Ahora, si escribimos web en la terminal de pprof, nos genera una representación gráfica de las funciones:</p>

<p><img src="/assets/images/posts/go-profiling-pprof001.svg" alt="go-profiling-pprof001" /></p>

<h2 id="en-runtime">En runtime</h2>

<p>pprof expone una interfaz HTTP para hacer profiling y recopilar datos en runtime. Este escenario es para cuando no tenemos una primera idea de por donde puede estar el cuello de botella, así que toca correr el software entero y disparar la acción que hace que nuestro programa dispare la CPU.</p>

<p>Para exponer la interfaz HTTP hay que escribir código, pero es bastante sencillo. La documentación está <a href="https://pkg.go.dev/net/http/pprof">aquí</a></p>

<p>Adaptemos el ejemplo anterior:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">(</span>
  <span class="s">"fmt"</span>
  <span class="n">_</span> <span class="s">"net/http/pprof"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
	<span class="k">go</span> <span class="k">func</span><span class="p">()</span> <span class="p">{</span>
		<span class="k">for</span> <span class="p">{</span>
			<span class="n">heavyComputation</span><span class="p">(</span><span class="m">1</span><span class="n">_000_000</span><span class="p">)</span>
			<span class="n">moderateComputation</span><span class="p">(</span><span class="m">1</span><span class="n">_000_000</span><span class="p">)</span>
			<span class="n">quickComputation</span><span class="p">(</span><span class="m">1</span><span class="n">_000_000</span><span class="p">)</span>
			<span class="n">time</span><span class="o">.</span><span class="n">Sleep</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">Second</span> <span class="o">*</span> <span class="m">5</span><span class="p">)</span>
		<span class="p">}</span>
	<span class="p">}()</span>

	<span class="c">// Start http server</span>
	<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"pprof at http://localhost:6060/debug/pprof/"</span><span class="p">)</span>
	<span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":6060"</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Corremos el programa y comenzamos a registrar datos:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Arrancar programa</span>
go run <span class="nb">.</span>
<span class="c"># Comenzar a almacenar datos de cpuprofile durante 30 segundos</span>
go tool pprof http://localhost:6060/debug/pprof/profile?seconds<span class="o">=</span>30
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Fetching profile over HTTP from http://localhost:6060/debug/pprof/profile?seconds=30
Saved profile in /home/andres/pprof/pprof.profiling.samples.cpu.004.pb.gz
File: profiling
Type: cpu
Time: Dec 9, 2024 at 3:42pm (WET)
Duration: 30s, Total samples = 50ms ( 0.17%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 50ms, 100% of 50ms total
      flat  flat%   sum%        cum   cum%
      30ms 60.00% 60.00%       30ms 60.00%  main.heavyComputation (inline)
      10ms 20.00% 80.00%       10ms 20.00%  main.moderateComputation (inline)
      10ms 20.00%   100%       10ms 20.00%  runtime.findRunnable
         0     0%   100%       40ms 80.00%  main.main.func1
         0     0%   100%       10ms 20.00%  runtime.mcall
         0     0%   100%       10ms 20.00%  runtime.park_m
         0     0%   100%       10ms 20.00%  runtime.schedule
(pprof)
</code></pre></div></div>

<h2 id="links">Links</h2>

<ul>
  <li>
    <p><a href="https://go.dev/blog/pprof">pprof</a></p>
  </li>
  <li>
    <p><a href="https://pkg.go.dev/runtime/pprof">pprof pkg</a></p>
  </li>
  <li>
    <p><a href="https://pkg.go.dev/net/http/pprof">net http pprof</a></p>
  </li>
</ul>]]></content><author><name>Andres</name></author><category term="Go" /><category term="Desarrollo" /><category term="dev" /><category term="profiling" /></entry><entry><title type="html">JSON en la terminal con jq</title><link href="http://hardfloat.es//blog/2024/04/02/json_en_la_terminal_con_jq.html" rel="alternate" type="text/html" title="JSON en la terminal con jq" /><published>2024-04-02T00:00:00-05:00</published><updated>2024-04-02T00:00:00-05:00</updated><id>http://hardfloat.es//blog/2024/04/02/json_en_la_terminal_con_jq</id><content type="html" xml:base="http://hardfloat.es//blog/2024/04/02/json_en_la_terminal_con_jq.html"><![CDATA[<p><a href="https://github.com/jqlang/jq">jq</a> es un procesador de JSON de la terminal. Tiene bastantes utilidades para procesar JSON desde la shell, transformarlos, buscar información, etc.</p>

<h3 id="mostrar-todo-el-json">Mostrar todo el Json</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>curl https://dummyjson.com/quotes | jq <span class="s1">'.'</span>
<span class="c"># Pipe con less y conservar el color</span>
<span class="nv">$ </span>curl https://dummyjson.com/quotes | jq <span class="nt">-C</span> <span class="s1">'.'</span> | less <span class="nt">-R</span>

</code></pre></div></div>

<h2 id="filtros">Filtros</h2>

<p>Los filtros nos permiten imprimir los elementos deseados de un JSON. Por ejemplo, el JSON de que hemos usado de quotes, tiene la siguiente forma:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"quotes"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w">
      </span><span class="nl">"quote"</span><span class="p">:</span><span class="w"> </span><span class="s2">"If You Can'T Make It Good, At Least Make It Look Good."</span><span class="p">,</span><span class="w">
      </span><span class="nl">"author"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Bill Gates"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">7</span><span class="p">,</span><span class="w">
      </span><span class="nl">"quote"</span><span class="p">:</span><span class="w"> </span><span class="s2">"If You Are Out To Describe The Truth, Leave Elegance To The Tailor."</span><span class="p">,</span><span class="w">
      </span><span class="nl">"author"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Albert Einstein"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Por lo tanto para imprimir solos los autores, debemos navegar de una forma similar. Traducido a un filtro de jq:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jq <span class="s1">'.quotes | .[] | .author'</span>

<span class="nv">$ </span>Bill Gates
<span class="nv">$ </span>Albert Einstein
</code></pre></div></div>

<p>Explicando un poquito el comando tendríamos:</p>

<ol>
  <li>“.quotes” Imprime el valor de la clave quotes.</li>
  <li>El caracter de “pipe” encadena filtros.</li>
  <li>”.[]” Imprime todo el contenido del array que cuelga de quotes.</li>
  <li>“.author” Imprime el contenido de las claves “author”.</li>
</ol>

<p>Para mostrar todos los autores de la API:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>curl https://dummyjson.com/quotes | jq <span class="s1">'.quotes | .[] | .author'</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>

3 <span class="s2">"Abdul Kalam"</span>
1 <span class="s2">"Abraham Lincoln"</span>
3 <span class="s2">"Abu Bakr (R.A)"</span>
2 <span class="s2">"Albert Einstein"</span>
2 <span class="s2">"Ali ibn Abi Talib (R.A)"</span>
1 <span class="s2">"Aristotle"</span>
1 <span class="s2">"Bill Gates"</span>
2 <span class="s2">"Mother Teresa"</span>
3 <span class="s2">"Muhammad Ali"</span>
1 <span class="s2">"Nelson Mandela"</span>
1 <span class="s2">"Oprah Winfrey"</span>
7 <span class="s2">"Rumi"</span>
1 <span class="s2">"Umar ibn Al-Khattāb (R.A)"</span>
1 <span class="s2">"Walt Disney"</span>
</code></pre></div></div>

<h2 id="select">Select</h2>

<p>Tambien podemos hacer búsquedas en un JSON y devolver el objeto que estamos buscando si conocemos una de sus claves.</p>

<p>Por ejemplo, dado el JSON de la quotes, queremos obtener todos los objetos cuyo autor sea “Albert Einstein”</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>curl https://dummyjson.com/quotes | jq <span class="s1">'.quotes | .[] | select(.author == "Albert Einstein")'</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">{</span>
  <span class="s2">"id"</span>: 7,
  <span class="s2">"quote"</span>: <span class="s2">"If You Are Out To Describe The Truth, Leave Elegance To The Tailor."</span>,
  <span class="s2">"author"</span>: <span class="s2">"Albert Einstein"</span>
<span class="o">}</span>
<span class="o">{</span>
  <span class="s2">"id"</span>: 28,
  <span class="s2">"quote"</span>: <span class="s2">"Technological Progress Is Like An Axe In The Hands Of A Pathological Criminal."</span>,
  <span class="s2">"author"</span>: <span class="s2">"Albert Einstein"</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="mostrar-las-claves">Mostrar las claves</h2>

<p>Otra utilidad excelente que posee es la de mostrar las claves de un json. Las claves se ordenan por orden alfabético.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>curl https://dummyjson.com/quotes | jq <span class="s1">'keys'</span>

<span class="o">[</span>
  <span class="s2">"limit"</span>,
  <span class="s2">"quotes"</span>,
  <span class="s2">"skip"</span>,
  <span class="s2">"total"</span>
<span class="o">]</span>
</code></pre></div></div>

<h2 id="seleccionar-múltiples-elementos">Seleccionar múltiples elementos</h2>

<p>También podemos seleccionar múltiples elementos de un json usando <code class="language-plaintext highlighter-rouge">{}</code>.
Por ejemplo, para seleccionar solo los autores y sus frases:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> curl https://dummyjson.com/quotes | jq <span class="s1">'.quotes | .[] | {author, quote}'</span>
</code></pre></div></div>

<p>Para más información visitar: <a href="https://jqlang.github.io/jq/manual/#basic-filters">https://jqlang.github.io/jq/manual/#basic-filters</a></p>]]></content><author><name>Andres</name></author><category term="jq" /><category term="json" /><category term="tools" /><summary type="html"><![CDATA[jq es un procesador de JSON de la terminal. Tiene bastantes utilidades para procesar JSON desde la shell, transformarlos, buscar información, etc.]]></summary></entry><entry><title type="html">Buscar capturas con tshark</title><link href="http://hardfloat.es//blog/2023/06/14/buscar_capturas_con_tshark.html" rel="alternate" type="text/html" title="Buscar capturas con tshark" /><published>2023-06-14T00:00:00-05:00</published><updated>2023-06-14T00:00:00-05:00</updated><id>http://hardfloat.es//blog/2023/06/14/buscar_capturas_con_tshark</id><content type="html" xml:base="http://hardfloat.es//blog/2023/06/14/buscar_capturas_con_tshark.html"><![CDATA[<p>Tshark es la versión de terminal de <a href="https://www.wireshark.org/">Wireshark</a>.
Permite capturar tráfico, aplicar filtros, abrir capturas, etc. La ventaja de
ser una aplicación de terminal es que permite que se puedan hacer scripts con
esta herramienta.</p>

<p>Para aplicar un filtro con tshark desde la terminal:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tshark <span class="nt">-Y</span> &lt;filter&gt; <span class="nt">-r</span> &lt;capture&gt;
</code></pre></div></div>

<p>El filtro para este tráfico en particular junto con tshark:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tshark <span class="nt">-Y</span> <span class="s1">'http and http.request.method == GET and http.request.full_uri contains "www.hardfloat.es"'</span> <span class="nt">-r</span> capture
</code></pre></div></div>

<p>Que devuelve:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   10   0.171128 192.168.1.134 → 172.104.241.7 HTTP 145 GET / HTTP/1.1
</code></pre></div></div>

<p>Un uso recurrente que le doy a esta herramienta es la de buscar capturas que
contengan un tipo de tráfico en particular. Por ejemplo, dado un directorio con
capturas, cuál de ellas tienen peticiones GET HTTP a hardfloat.com.</p>

<p>Con poder aplicar el filtro ya nos soluciona bastantes problemas, solo tenemos
que hacer un pequeño script que nos devuelva el nombre de la captura en caso de
que el filtro devuelva un resultado. Nombrando al fichero find_captures.sh:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="nv">WFILTER</span><span class="o">=</span><span class="nv">$1</span>
<span class="nv">CAPTURE_FILE</span><span class="o">=</span><span class="nv">$2</span>

<span class="nv">OUTPUT</span><span class="o">=</span><span class="si">$(</span> tshark <span class="nt">-Y</span> <span class="s2">"</span><span class="nv">$WFILTER</span><span class="s2">"</span> <span class="nt">-r</span> <span class="nv">$CAPTURE_FILE</span> <span class="si">)</span>
<span class="k">if</span> <span class="o">[</span> <span class="o">!</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$OUTPUT</span><span class="s2">"</span> <span class="o">]</span>
<span class="k">then
    </span><span class="nb">echo</span> <span class="nv">$CAPTURE_FILE</span>
<span class="k">fi</span>
</code></pre></div></div>

<p>Y el script completo:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>find &lt;capture <span class="nb">dir</span><span class="o">&gt;</span> <span class="nt">-name</span> <span class="s1">'*.cap'</span> <span class="nt">-exec</span> ./find_capture.sh <span class="s1">'http and http.request.method == GET and http.request.full_uri contains "www.hardfloat.es"'</span> <span class="o">{}</span> <span class="se">\;</span>
</code></pre></div></div>]]></content><author><name>Andres</name></author><category term="tools" /><category term="wireshark" /><category term="linux" /><summary type="html"><![CDATA[Tshark es la versión de terminal de Wireshark. Permite capturar tráfico, aplicar filtros, abrir capturas, etc. La ventaja de ser una aplicación de terminal es que permite que se puedan hacer scripts con esta herramienta.]]></summary></entry><entry><title type="html">Go parte 4 - Testing</title><link href="http://hardfloat.es//blog/2023/05/24/go-parte4-testing.html" rel="alternate" type="text/html" title="Go parte 4 - Testing" /><published>2023-05-24T00:00:00-05:00</published><updated>2023-05-24T00:00:00-05:00</updated><id>http://hardfloat.es//blog/2023/05/24/go-parte4-testing</id><content type="html" xml:base="http://hardfloat.es//blog/2023/05/24/go-parte4-testing.html"><![CDATA[<ul id="markdown-toc">
  <li><a href="#intro" id="markdown-toc-intro">Intro</a></li>
  <li><a href="#testing-package" id="markdown-toc-testing-package">Testing package</a></li>
  <li><a href="#unit-test" id="markdown-toc-unit-test">Unit test</a></li>
  <li><a href="#table-driven-test" id="markdown-toc-table-driven-test">Table-Driven test</a></li>
  <li><a href="#coverage" id="markdown-toc-coverage">Coverage</a></li>
  <li><a href="#benchmark" id="markdown-toc-benchmark">Benchmark</a></li>
  <li><a href="#fuzz-test" id="markdown-toc-fuzz-test">Fuzz test</a></li>
  <li><a href="#testify" id="markdown-toc-testify">Testify</a></li>
  <li><a href="#links" id="markdown-toc-links">Links</a></li>
</ul>

<h2 id="intro">Intro</h2>

<h2 id="testing-package">Testing package</h2>

<p>El ecosistema de Go trae soporte nativo para escribir y ejecutar tests
automáticos. El paquete <a href="https://pkg.go.dev/testing">testing</a> es el que provee
soporte para la escritura de tests.</p>

<h2 id="unit-test">Unit test</h2>

<p>Para definir una <em>test suite</em> es necesario que el fichero termine en:
<em>_test.go</em>. Definir un <em>test case</em> se tiene que escribir una función con la
forma:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">TestXxx</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span>
</code></pre></div></div>

<p>Donde Xxx es el nombre del caso de prueba y <em>debe comenzar con mayúsculas</em>.</p>

<p>Para correr los tests basta con ejecutar <em>go test</em> y automáticamente buscará las
suites y correrá los tests.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go <span class="nb">test</span>
</code></pre></div></div>

<p>Pongamos un ejemplo sencillo para ilustrar los conceptos. Supongamos un paquete
que se encarga de realizar operaciones matemáticas: sumas, restas,
multiplicaciones y divisiones con su respectivo test.</p>

<ul>
  <li>math.go</li>
</ul>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">func</span> <span class="n">Add</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>math_test.go</li>
</ul>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="s">"testing"</span>

<span class="k">func</span> <span class="n">TestAddZeroValues</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">res</span> <span class="o">:=</span> <span class="n">Add</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">res</span> <span class="o">!=</span> <span class="m">0</span> <span class="p">{</span>
        <span class="n">t</span><span class="o">.</span><span class="n">Errorf</span><span class="p">(</span><span class="s">"Expected 0, got %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">res</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">TestSubZeroValues</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">res</span> <span class="o">:=</span> <span class="n">Sub</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">res</span> <span class="o">!=</span> <span class="m">0</span> <span class="p">{</span>
        <span class="n">t</span><span class="o">.</span><span class="n">Errorf</span><span class="p">(</span><span class="s">"Expected 0, got %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">res</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Por último para ejecutar el test y mostrar la salida de cada test:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go <span class="nb">test</span> <span class="nt">-v</span>
</code></pre></div></div>

<h2 id="table-driven-test">Table-Driven test</h2>

<p>El table-driven test es un concepto para la escritura de tests que consiste en
escribir una matriz que contenga las entradas y salidas de los esperadas para un
caso de prueba. Esta técnica nos evita tener que escribir múltiples casos de
prueba para diferentes entradas.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">TestTableDrivenDiv</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">var</span> <span class="n">table</span> <span class="o">=</span> <span class="p">[]</span><span class="k">struct</span> <span class="p">{</span>
        <span class="n">name</span> <span class="kt">string</span>
        <span class="n">input_a</span> <span class="kt">int</span>
        <span class="n">input_b</span> <span class="kt">int</span>
        <span class="n">expected</span> <span class="kt">int</span>
    <span class="p">}{</span>
        <span class="p">{</span><span class="s">"Divide 1/1"</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">1</span><span class="p">},</span>
        <span class="p">{</span><span class="s">"Divide -1/1"</span><span class="p">,</span> <span class="o">-</span><span class="m">1</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="o">-</span><span class="m">1</span><span class="p">},</span>
        <span class="p">{</span><span class="s">"Divide 0/1"</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">},</span>
        <span class="p">{</span><span class="s">"Divide 2/1"</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">},</span>
    <span class="p">}</span>
    <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">test</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">table</span> <span class="p">{</span>
        <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="n">test</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">res</span> <span class="o">:=</span> <span class="n">Div</span><span class="p">(</span><span class="n">test</span><span class="o">.</span><span class="n">input_a</span><span class="p">,</span> <span class="n">test</span><span class="o">.</span><span class="n">input_b</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">res</span> <span class="o">!=</span> <span class="n">test</span><span class="o">.</span><span class="n">expected</span> <span class="p">{</span>
                <span class="n">t</span><span class="o">.</span><span class="n">Errorf</span><span class="p">(</span><span class="s">"Expected %d, got %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">test</span><span class="o">.</span><span class="n">expected</span><span class="p">,</span> <span class="n">res</span><span class="p">)</span>
            <span class="p">}</span>
        <span class="p">})</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="coverage">Coverage</h2>

<p>Se puede conocer el porcentaje de cobertura de nuestro código con go test:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go <span class="nb">test</span> <span class="nt">-cover</span>
</code></pre></div></div>

<h2 id="benchmark">Benchmark</h2>

<p>Para escribir benchmarks:</p>

<p>Las funciones con la forma:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">BenchmarkXxx</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">B</span><span class="p">)</span>
</code></pre></div></div>

<p>Se consideran <em>benchmarks</em></p>

<p>Un ejemplo de Benchmark:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">BenchmarkRandInt</span><span class="p">(</span><span class="n">b</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">B</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">b</span><span class="o">.</span><span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
        <span class="n">rand</span><span class="o">.</span><span class="n">Int</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Para correr un benchmark se tiene que correr explícitamente con:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go <span class="nb">test</span> <span class="nt">-bench</span><span class="o">=</span><span class="nb">.</span>
</code></pre></div></div>

<h2 id="fuzz-test">Fuzz test</h2>

<p>Fuzzy testing es una técnica de testing que consiste en introducir entradas no
esperadas al elemento de prueba.</p>

<p>Go también provee de esta funcionalidad de forma nativa. Para definir un <em>Fuzz
test</em>:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">FuzzXxx</span> <span class="p">(</span><span class="n">f</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">F</span><span class="p">)</span>
</code></pre></div></div>

<p>Para ilustrarlo, remotomemos el ejemplo anterior y creemos un <em>Fuzz test</em> para
la función <em>Div</em>:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">FuzzDiv</span><span class="p">(</span><span class="n">f</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">F</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">f</span><span class="o">.</span><span class="n">Fuzz</span><span class="p">(</span><span class="k">func</span> <span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">Div</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
    <span class="p">})</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Como se puede ver f.Fuzz acepta múltiples argumentos para usar como entrada a
nuestro caso de prueba.</p>

<p>Deliberadamente he dejado que el denominador pueda tener el valor cero y por lo
tanto la función <em>Div</em> contenga un error. El <em>Fuzz test</em> va a conseguir
reproducir esa condición de error. Para ejecutarlo y ver la salida:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>go <span class="nb">test</span> <span class="nt">-fuzz</span><span class="o">=</span><span class="nb">.</span>

fuzz: elapsed: 0s, gathering baseline coverage: 0/1 completed
failure <span class="k">while </span>testing seed corpus entry: FuzzDiv/7bef6c8ac710a3fe
fuzz: elapsed: 0s, gathering baseline coverage: 0/1 completed
<span class="nt">---</span> FAIL: FuzzDiv <span class="o">(</span>0.01s<span class="o">)</span>
    <span class="nt">---</span> FAIL: FuzzDiv <span class="o">(</span>0.00s<span class="o">)</span>
        testing.go:1485: panic: runtime error: integer divide by zero
            goroutine 20 <span class="o">[</span>running]:
            runtime/debug.Stack<span class="o">()</span>
                /usr/lib/go/src/runtime/debug/stack.go:24 +0x9e
            testing.tRunner.func1<span class="o">()</span>
                /usr/lib/go/src/testing/testing.go:1485 +0x1f6
            panic<span class="o">({</span>0x5c32e0, 0x721fc0<span class="o">})</span>
                /usr/lib/go/src/runtime/panic.go:884 +0x213
            test.Div<span class="o">(</span>...<span class="o">)</span>
                /tmp/test/math.go:16
            test.FuzzDiv.func1<span class="o">(</span>0x0?, 0x0?, 0x0?<span class="o">)</span>
                /tmp/test/math_test.go:64 +0x3d
            reflect.Value.call<span class="o">({</span>0x5bf720?, 0x5fc668?, 0x13?<span class="o">}</span>, <span class="o">{</span>0x5ed030, 0x4<span class="o">}</span>, <span class="o">{</span>0xc0000a01e0, 0x3, 0x4?<span class="o">})</span>
                /usr/lib/go/src/reflect/value.go:586 +0xb0b
            reflect.Value.Call<span class="o">({</span>0x5bf720?, 0x5fc668?, 0x6f31a0?<span class="o">}</span>, <span class="o">{</span>0xc0000a01e0?, 0x5ec720?, 0xc00009a058?<span class="o">})</span>
                /usr/lib/go/src/reflect/value.go:370 +0xbc
            testing.<span class="o">(</span><span class="k">*</span>F<span class="o">)</span>.Fuzz.func1.1<span class="o">(</span>0x0?<span class="o">)</span>
                /usr/lib/go/src/testing/fuzz.go:335 +0x3f3
            testing.tRunner<span class="o">(</span>0xc0000824e0, 0xc0000b0090<span class="o">)</span>
                /usr/lib/go/src/testing/testing.go:1576 +0x10b
            created by testing.<span class="o">(</span><span class="k">*</span>F<span class="o">)</span>.Fuzz.func1
                /usr/lib/go/src/testing/fuzz.go:322 +0x5b9


FAIL
<span class="nb">exit </span>status 1
FAIL    <span class="nb">test    </span>0.008s
</code></pre></div></div>

<h2 id="testify">Testify</h2>

<p><a href="https://github.com/stretchr/testify">Testify</a> es un paquete de pruebas
unitarias de Go que proporciona funciones adicionales y mejoras a la biblioteca
estándar de pruebas de Go. Testify usa una sintaxis similar a otros frameworks
de pruebas de otros lenguajes de programación.</p>

<p>Por ejemplo testify provee del paquete <em>assert</em> que provee una sintaxis legible
para hacer nuestros tests como:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">()</span>
<span class="n">assert</span><span class="o">.</span><span class="n">True</span><span class="p">()</span>
<span class="n">assert</span><span class="o">.</span><span class="n">Nil</span><span class="p">()</span>
</code></pre></div></div>

<p>Para instalar testify:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">go</span> <span class="n">get</span> <span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">stretchr</span><span class="o">/</span><span class="n">testify</span>
</code></pre></div></div>

<p>Usando testify en nuestro proyecto:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
        <span class="s">"github.com/stretchr/testify/assert"</span>
        <span class="s">"testing"</span>
       <span class="p">)</span>

<span class="k">func</span> <span class="n">TestTableDrivenDiv</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">var</span> <span class="n">table</span> <span class="o">=</span> <span class="p">[]</span><span class="k">struct</span> <span class="p">{</span>
        <span class="n">name</span>     <span class="kt">string</span>
            <span class="n">input_a</span>  <span class="kt">int</span>
            <span class="n">input_b</span>  <span class="kt">int</span>
            <span class="n">expected</span> <span class="kt">int</span>
    <span class="p">}{</span>
        <span class="p">{</span><span class="s">"Divide 1/1"</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">1</span><span class="p">},</span>
            <span class="p">{</span><span class="s">"Divide -1/1"</span><span class="p">,</span> <span class="o">-</span><span class="m">1</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="o">-</span><span class="m">1</span><span class="p">},</span>
            <span class="p">{</span><span class="s">"Divide 0/1"</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">},</span>
            <span class="p">{</span><span class="s">"Divide 2/1"</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">},</span>
    <span class="p">}</span>
    <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">test</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">table</span> <span class="p">{</span>
        <span class="n">t</span><span class="o">.</span><span class="n">Run</span><span class="p">(</span><span class="n">test</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">testing</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">assert</span><span class="o">.</span><span class="n">Equal</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">Div</span><span class="p">(</span><span class="n">test</span><span class="o">.</span><span class="n">input_a</span><span class="p">,</span> <span class="n">test</span><span class="o">.</span><span class="n">input_b</span><span class="p">),</span> <span class="n">test</span><span class="o">.</span><span class="n">expected</span><span class="p">,</span> <span class="s">""</span><span class="p">)</span>
                <span class="p">})</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="links">Links</h2>

<p><a href="https://pkg.go.dev/testing">https://pkg.go.dev/testing</a></p>

<p><a href="https://blog.jetbrains.com/go/2022/11/22/comprehensive-guide-to-testing-in-go/#WritingFuzzTests">https://blog.jetbrains.com/go/2022/11/22/comprehensive-guide-to-testing-in-go/#WritingFuzzTests</a></p>]]></content><author><name>Andres</name></author><category term="Go" /><category term="Desarrollo" /><category term="dev" /></entry><entry><title type="html">Go parte 3 - Módulos y paquetes</title><link href="http://hardfloat.es//blog/2023/05/17/go-parte3-modulos-y-paquetes.html" rel="alternate" type="text/html" title="Go parte 3 - Módulos y paquetes" /><published>2023-05-17T00:00:00-05:00</published><updated>2023-05-17T00:00:00-05:00</updated><id>http://hardfloat.es//blog/2023/05/17/go-parte3-modulos-y-paquetes</id><content type="html" xml:base="http://hardfloat.es//blog/2023/05/17/go-parte3-modulos-y-paquetes.html"><![CDATA[<ul id="markdown-toc">
  <li><a href="#packages-vs-modules" id="markdown-toc-packages-vs-modules">Packages vs modules</a></li>
  <li><a href="#packages" id="markdown-toc-packages">Packages</a>    <ul>
      <li><a href="#main-package" id="markdown-toc-main-package">main package</a></li>
    </ul>
  </li>
  <li><a href="#modules" id="markdown-toc-modules">Modules</a>    <ul>
      <li><a href="#crear-módulos" id="markdown-toc-crear-módulos">Crear módulos</a></li>
      <li><a href="#importar-paquetes-dentro-de-nuestro-módulo" id="markdown-toc-importar-paquetes-dentro-de-nuestro-módulo">Importar paquetes dentro de nuestro módulo</a></li>
      <li><a href="#agregar-módulos-de-terceros" id="markdown-toc-agregar-módulos-de-terceros">Agregar módulos de terceros</a></li>
    </ul>
  </li>
  <li><a href="#links" id="markdown-toc-links">Links</a></li>
</ul>

<h2 id="packages-vs-modules">Packages vs modules</h2>

<p>Un paquete en Go es una colección de archivos Go en un mismo directorio, que se
utilizan para proporcionar una funcionalidad específica y reutilizable en una
aplicación Go.</p>

<p>Por otro lado, un módulo en Go es una colección de paquetes Go que se utilizan
juntos como una unidad lógica. Los módulos permiten especificar y gestionar las
dependencias de una aplicación Go de forma más precisa y confiable. Cada módulo
tiene su propio archivo go.mod que describe las dependencias y la versión de
cada paquete utilizado.</p>

<p>Por otro lado, un módulo en Go es una colección de paquetes Go en un arbol de
directorio con un fichero <em>go.mod</em> en el directorio principal.</p>

<h2 id="packages">Packages</h2>

<p>Como se ha dicho, un paquete de Go es una colección de archivos en un mismo
directorio. La primera línea de un archivo go se declara la pertenencia a un
paquete con la sintaxis:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="o">&lt;</span><span class="k">package</span> <span class="n">name</span><span class="o">&gt;</span>
</code></pre></div></div>

<p>Por convención el nombre del directorio y del paquete deben ser el mismo.</p>

<p>Por ejemplo creamos la siguiente estructura de directorios:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir </span>webapp
<span class="nb">cd </span>webapp
<span class="nb">mkdir </span>models
</code></pre></div></div>

<p>Y creamos dos ficheros en el directorio models:</p>

<ul>
  <li>user.go</li>
</ul>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">models</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"fmt"</span>
<span class="p">)</span>

<span class="k">type</span> <span class="n">User</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">Name</span> <span class="kt">string</span>
    <span class="n">Age</span> <span class="kt">int</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>chatroom.go</li>
</ul>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">models</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"fmt"</span>
<span class="p">)</span>

<span class="k">type</span> <span class="n">ChatRoom</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">Name</span> <span class="kt">string</span>
    <span class="n">Users</span> <span class="p">[]</span><span class="n">User</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Ambos ficheros pertenecen al mismo package: <em>models</em>. Otro detalle importante,
es que las <strong>funciones/variables etc declaradas en un mismo paquete son visibles
para todos los archivos go por defecto</strong>, no hace falta hacer <em>import</em>.</p>

<p>Como se puede observar la <em>struct</em> <em>chatroom</em> utiliza la <em>struct</em> <em>User</em> a pesar
de que está definida en otro fichero.</p>

<h3 id="main-package">main package</h3>

<p>El nombre de paquete <em>main</em> está reservado para el punto de entrada de la
aplicación y debe contener la función <em>main</em> que es la función de entrada de la
aplicación</p>

<h2 id="modules">Modules</h2>

<h3 id="crear-módulos">Crear módulos</h3>

<p>Pasos para crear un <em>go module</em></p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">go</span> <span class="n">mod</span> <span class="n">init</span> <span class="o">&lt;</span><span class="n">module</span> <span class="n">name</span><span class="o">&gt;</span>
</code></pre></div></div>

<p>Con el comando anterior debería haberse creado un fichero llamado <em>go.mod</em> que
contiene todas las dependencias que utilicemos en el proyecto.</p>

<p>Al haber creado un módulo todos los comandos que lancemos como, go build, test,
run, fmt, etc se harán sobre todos los paquetes del módulo.</p>

<h3 id="importar-paquetes-dentro-de-nuestro-módulo">Importar paquetes dentro de nuestro módulo</h3>

<p>Para importar módulos propios tenemos que respetar obviamente las reglas para
crear paquetes. Además en el import se debe poner la ruta absoluta hacia el
módulo que vayamos a importar.</p>

<p>Para importar un paquete dentro de nuestro módulo hay que escribir el nombre que
le hayamos dado al módulo seguido de la ruta hacia el paquete:</p>

<p>Siguiendo con el ejemplo, creemos un módulo llamado <em>webapp</em>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go mod init webapp
</code></pre></div></div>

<p>Creamos un archivo main.go para importar los modelos creados anteriormente.</p>

<p>** Los imports utilizan rutas absolutas**. Siendo el origen el nombre del módulo.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="c">//Al estar en package name hay que importar los paquetes</span>
<span class="c">//desados</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"webapp/models"</span> <span class="c">//Notar como se usa el nombre del módulo seguido de la ruta</span>
    <span class="c">//hacia el paquete</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">user</span> <span class="o">:=</span> <span class="n">models</span><span class="o">.</span><span class="n">User</span><span class="p">{</span><span class="s">"Foo"</span><span class="p">,</span> <span class="m">25</span><span class="p">}</span>
    <span class="n">chatroom</span> <span class="o">:=</span> <span class="n">models</span><span class="o">.</span><span class="n">ChatRoom</span><span class="p">{</span><span class="s">"GoDev"</span><span class="p">,</span> <span class="no">nil</span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="agregar-módulos-de-terceros">Agregar módulos de terceros</h3>

<p>Para agregar una dependencia con un módulo de terceros se utiliza el comando:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go get &lt;url to module&gt;
</code></pre></div></div>

<p>Y se agregaría la información de esta dependencia en el fichero <em>go.mod</em></p>

<h2 id="links">Links</h2>

<p><a href="https://www.digitalocean.com/community/tutorials/how-to-use-go-modules">https://www.digitalocean.com/community/tutorials/how-to-use-go-modules</a></p>]]></content><author><name>Andres</name></author><category term="Go" /><category term="Desarrollo" /><category term="dev" /></entry><entry><title type="html">Go parte 2 - Concurrencia</title><link href="http://hardfloat.es//blog/2023/05/15/go-parte2-concurrencia.html" rel="alternate" type="text/html" title="Go parte 2 - Concurrencia" /><published>2023-05-15T00:00:00-05:00</published><updated>2023-05-15T00:00:00-05:00</updated><id>http://hardfloat.es//blog/2023/05/15/go-parte2-concurrencia</id><content type="html" xml:base="http://hardfloat.es//blog/2023/05/15/go-parte2-concurrencia.html"><![CDATA[<ul id="markdown-toc">
  <li><a href="#intro" id="markdown-toc-intro">Intro</a></li>
  <li><a href="#goroutine" id="markdown-toc-goroutine">Goroutine</a></li>
  <li><a href="#channels" id="markdown-toc-channels">Channels</a>    <ul>
      <li><a href="#sincronización-usando-channels" id="markdown-toc-sincronización-usando-channels">Sincronización usando channels</a></li>
      <li><a href="#buffered-and-unbuffered-channels" id="markdown-toc-buffered-and-unbuffered-channels">Buffered and unbuffered channels</a></li>
      <li><a href="#closing-channels" id="markdown-toc-closing-channels">Closing channels</a></li>
      <li><a href="#channel-directions" id="markdown-toc-channel-directions">Channel directions</a></li>
      <li><a href="#select" id="markdown-toc-select">Select</a>        <ul>
          <li><a href="#timeouts" id="markdown-toc-timeouts">Timeouts</a></li>
        </ul>
      </li>
    </ul>
  </li>
  <li><a href="#waitgroup" id="markdown-toc-waitgroup">WaitGroup</a></li>
  <li><a href="#workers-pool" id="markdown-toc-workers-pool">Workers pool</a></li>
  <li><a href="#links" id="markdown-toc-links">Links</a></li>
</ul>

<h2 id="intro">Intro</h2>

<p>Las primitivas para escribir código concurrente es uno de los puntos más fuertes
de Go. Estas primitivas son las <strong>goroutines</strong> y los <strong>channels</strong></p>

<p>Para no estar todo el rato escribiendo <em>goroutine</em> usaré como sinónimo rutina y
para los <em>channels</em> usaré canal.</p>

<ul>
  <li>Goroutines</li>
</ul>

<p>Las <em>goroutines</em> son hilos de ejecución ligeros que corren en el mismo espacio
de direcciones. Son ligeros en el sentido de que el coste es reservar espacio en
el stack y crecen reservando (y eliminando) memoria en el <em>heap</em> según sea
necesario. Las <em>goroutines</em> se multiplexan en múltiples hilos del sistema
operativo; si una rutina se bloquea, por E/S u otro motivo, otras
<em>goroutines</em> siguen ejecutándose.</p>

<p>Al compartir espacio de memoria el acceso a variables compartidas debe
sincronizarse.</p>

<ul>
  <li>Channels</li>
</ul>

<p>Los <strong>channels</strong> se utilizan para compartir información entre las
<strong>goroutines</strong>.</p>

<p>Por defecto enviar y recibir son bloqueantes hasta que el emisor y el receptor
estén listos para la comunicación.</p>

<p>Esto se verá mejor con los ejemplos a lo largo del post.</p>

<ul>
  <li>Waitgroup</li>
</ul>

<p>Un <em>Waitgroup</em> se utiliza para coordinar la ejecución de múltiples <em>goroutines</em>
y esperar a que todas ellas finalicen antes de continuar con la ejecución del
programa.</p>

<h2 id="goroutine">Goroutine</h2>

<p>La sintaxis para lanzar una rutina es sencillo, basta con escribir delante de
una función la palabra reservada <em>go</em>.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
  <span class="s">"fmt"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">say</span><span class="p">(</span><span class="n">s</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">go</span> <span class="n">say</span><span class="p">(</span><span class="s">"world"</span><span class="p">)</span>
    <span class="n">say</span><span class="p">(</span><span class="s">"hello"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>El resultado del programa anterior es simplemente “hello” en lugar de “world
hello”. Esto merece una breve explicación.</p>

<p>Cuando el programa se encuentra con: go say(“world”) ejecuta la función say en
una rutina de forma independiente y sale inmediatamente. La siguiente línea es
la función regular say(“hello”) que pertenece al hilo principal, al finalizar
como el hilo principal ha terminado, el programa termina y finaliza.</p>

<p>Si queremos ver como se ejecuta la rutina agregamos un delay en el hilo
principal para que le de tiempo a la rutina a ejecutarse. Esta no es la manera
correcta de trabajar, para eso están los canales.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"fmt"</span>
    <span class="s">"time"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">say</span><span class="p">(</span><span class="n">s</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">go</span> <span class="n">say</span><span class="p">(</span><span class="s">"world"</span><span class="p">)</span>
    <span class="n">say</span><span class="p">(</span><span class="s">"hello"</span><span class="p">)</span>
    <span class="n">time</span><span class="o">.</span><span class="n">Sleep</span><span class="p">(</span><span class="m">100</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Millisecond</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="channels">Channels</h2>

<p>Un objeto <strong>channel</strong> sirve para enviar y recibir datos a través de el.
Un objeto de tipo <strong>channel</strong> se crea con la función <em>make</em>.</p>

<p>El operador para utilizar los canales es: <em>&lt;-</em></p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ch</span> <span class="o">&lt;-</span> <span class="n">v</span> <span class="c">//Send v to channel ch</span>
<span class="n">v</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">ch</span> <span class="c">//Receive from ch and assign it to value v</span>
<span class="c">//the data flows in the direction of the arrow</span>
</code></pre></div></div>

<p>Veamos un pequeño código que devuelve los números impares de una lista de
números. El cálculo lo hace una rutina y el resultado se devuelve a través de un
canal</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
<span class="s">"fmt"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">is_odd</span><span class="p">(</span><span class="n">n</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
    <span class="k">if</span> <span class="n">n</span> <span class="o">%</span> <span class="m">2</span> <span class="o">!=</span> <span class="m">0</span> <span class="p">{</span>
        <span class="k">return</span> <span class="no">true</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="no">false</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">get_odd_numbers</span><span class="p">(</span><span class="n">ch</span> <span class="k">chan</span> <span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="n">num_list</span> <span class="p">[]</span><span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">odd_num_list</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span> <span class="m">1</span><span class="p">)</span> <span class="c">//Create a slice with at least 1 element</span>
    <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">num</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">num_list</span> <span class="p">{</span>
        <span class="k">if</span> <span class="n">is_odd</span><span class="p">(</span><span class="n">num</span><span class="p">)</span> <span class="p">{</span>
            <span class="c">//the append func will resize the slice</span>
            <span class="n">odd_num_list</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">odd_num_list</span><span class="p">,</span> <span class="n">num</span><span class="p">)</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="n">ch</span> <span class="o">&lt;-</span> <span class="n">odd_num_list</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">num_list</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>
    <span class="c">//Create a slice with the first 10 numbers</span>
    <span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">num_list</span> <span class="p">{</span>
        <span class="n">num_list</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span>
    <span class="p">}</span>

    <span class="n">ch</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="p">[]</span><span class="kt">int</span><span class="p">)</span>
    <span class="c">//calculate the odd numbers in a goroutine</span>
    <span class="k">go</span> <span class="n">get_odd_numbers</span><span class="p">(</span><span class="n">ch</span><span class="p">,</span> <span class="n">num_list</span><span class="p">)</span>
    <span class="c">//get the result from goroutine</span>
    <span class="n">odd_num_list</span> <span class="o">:=</span> <span class="o">&lt;-</span> <span class="n">ch</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"odd numbers = %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">odd_num_list</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Como se puede observar utilizar concurrencia es realmente sencillo.</p>

<h3 id="sincronización-usando-channels">Sincronización usando channels</h3>

<p>Recuperando el ejemplo anterior veamos un fragmento de código para sincronizar
una goroutine y el hilo principal</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
   <span class="s">"fmt"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">say</span><span class="p">(</span><span class="n">done</span> <span class="k">chan</span> <span class="kt">bool</span><span class="p">,</span> <span class="n">s</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
    <span class="n">done</span> <span class="o">&lt;-</span> <span class="no">true</span> <span class="c">// set done to true</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">done</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">bool</span><span class="p">)</span>
    <span class="k">go</span> <span class="n">say</span><span class="p">(</span><span class="n">done</span><span class="p">,</span> <span class="s">"Hello world"</span><span class="p">)</span>
    <span class="o">&lt;-</span> <span class="n">done</span> <span class="c">//Wait for goroutine to finish</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="buffered-and-unbuffered-channels">Buffered and unbuffered channels</h3>

<p>La diferencia entre un buffered y unbuffered channel radica en que se puede
crear un canal con un tamaño determinado, de manera que se puede ir enviando
encolando mensajes hasta llenarse, y cuando lo haga se envía todos los mensajes
de una.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">unbuffered_channel</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">int</span><span class="p">)</span>

<span class="c">//Sends to a buffered channel. It blocks when the buffer is full and the</span>
<span class="c">//receiver blocks when buffer is empty</span>
<span class="n">buffered_channel</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">int</span><span class="p">,</span> <span class="m">100</span><span class="p">)</span>
</code></pre></div></div>

<h3 id="closing-channels">Closing channels</h3>

<p>Cerrar un canal indica que el <em>sender</em> no va a enviar más valores al <em>receiver</em>.
Solo el <strong>sender</strong> debe cerrar un canal, <strong>nunca el receiver</strong>.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
  <span class="s">"fmt"</span>
<span class="p">)</span>

<span class="c">//sender</span>
<span class="k">func</span> <span class="n">linear_gen</span><span class="p">(</span><span class="n">c</span> <span class="k">chan</span> <span class="kt">int</span><span class="p">,</span> <span class="n">max</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">max</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
        <span class="n">c</span> <span class="o">&lt;-</span> <span class="n">i</span>
    <span class="p">}</span>
    <span class="nb">close</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">receiver</span><span class="p">(</span><span class="n">c</span> <span class="k">chan</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
    <span class="c">//loops until channel c is closed</span>
    <span class="k">for</span> <span class="n">v</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">c</span> <span class="p">{</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">receiver2</span><span class="p">(</span><span class="n">c</span> <span class="k">chan</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">{</span>
        <span class="c">//when ok is false means no more values</span>
        <span class="c">//will be received</span>
        <span class="n">n</span><span class="p">,</span> <span class="n">ok</span> <span class="o">:=</span> <span class="o">&lt;-</span> <span class="n">c</span>
        <span class="k">if</span> <span class="o">!</span><span class="n">ok</span> <span class="p">{</span>
            <span class="k">break</span>
        <span class="p">}</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">c</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">int</span><span class="p">,</span> <span class="m">20</span><span class="p">)</span>

    <span class="k">go</span> <span class="n">linear_gen</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="m">100</span><span class="p">)</span>
    <span class="n">receiver</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="channel-directions">Channel directions</h3>

<p>Cuando se usan los canales como argumentos de una función se puede especificar
si un canal es solo de entrada o solo de salida. La dirección del canal se
comprueba en tiempo de compilación, si se usa erróneamente se lanza un error de
compilación.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">func</span> <span class="n">echo</span><span class="p">(</span><span class="n">input</span> <span class="o">&lt;-</span><span class="k">chan</span> <span class="kt">string</span><span class="p">,</span> <span class="n">output</span> <span class="k">chan</span><span class="o">&lt;-</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">msg</span> <span class="o">:=</span> <span class="o">&lt;-</span> <span class="n">input</span>
    <span class="n">output</span> <span class="o">&lt;-</span> <span class="n">msg</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">input</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">string</span><span class="p">)</span>
    <span class="n">output</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">string</span><span class="p">)</span>

    <span class="k">go</span> <span class="n">echo</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="n">output</span><span class="p">)</span>
    <span class="n">input</span> <span class="o">&lt;-</span> <span class="s">"Hello world"</span>

    <span class="n">msg</span> <span class="o">:=</span> <span class="o">&lt;-</span> <span class="n">output</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">msg</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="select">Select</h3>

<p>La instrucción <em>select</em> permite esperar en diferentes canales. Esta sentencia
bloquea la ejecución de una <em>goroutine</em> hasta que uno de los casos del <em>select</em>
se puedan ejecutar. Si múltiples canales están listos selecciona uno
aleatoriamente.</p>

<p>Además la sentencia <em>select</em> cuenta con un <em>default case</em> que se ejecuta cuando
ningún canal esté listo.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"fmt"</span>
    <span class="s">"time"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">ch1</span><span class="p">,</span> <span class="n">ch2</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">string</span><span class="p">),</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">string</span><span class="p">)</span>

    <span class="k">go</span> <span class="k">func</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">ch1</span> <span class="o">&lt;-</span> <span class="s">"goroutine 1"</span>
    <span class="p">}()</span>
    <span class="k">go</span> <span class="k">func</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">ch2</span> <span class="o">&lt;-</span> <span class="s">"goroutine 2"</span>
    <span class="p">}()</span>


    <span class="c">//delay necessary to give time to goroutine to run</span>
    <span class="n">time</span><span class="o">.</span><span class="n">Sleep</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">Second</span> <span class="o">*</span> <span class="m">1</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="m">5</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
        <span class="k">select</span> <span class="p">{</span>
        <span class="k">case</span> <span class="n">msg1</span> <span class="o">:=</span> <span class="o">&lt;-</span> <span class="n">ch1</span><span class="o">:</span>
            <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">msg1</span><span class="p">)</span>
        <span class="k">case</span> <span class="n">msg2</span> <span class="o">:=</span> <span class="o">&lt;-</span> <span class="n">ch2</span><span class="o">:</span>
            <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">msg2</span><span class="p">)</span>
        <span class="k">default</span><span class="o">:</span>
            <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"default select case</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

</code></pre></div></div>

<h4 id="timeouts">Timeouts</h4>

<p>También es posible utilizar timeouts para evitar tener que estar esperando un
mensaje a través de un canal. Se puede utilizar en conjunto con la sentencia
<em>select</em>.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"fmt"</span>
    <span class="s">"time"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">long_running_task</span><span class="p">(</span><span class="n">result</span> <span class="k">chan</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">time</span><span class="o">.</span><span class="n">Sleep</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">Hour</span><span class="p">)</span>
    <span class="n">result</span> <span class="o">&lt;-</span> <span class="m">0</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">c</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">int</span><span class="p">)</span>

    <span class="k">go</span> <span class="n">long_running_task</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>

    <span class="k">select</span> <span class="p">{</span>
    <span class="k">case</span> <span class="n">result</span> <span class="o">:=</span> <span class="o">&lt;-</span> <span class="n">c</span><span class="o">:</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Long running task result=%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">result</span><span class="p">)</span>
    <span class="k">case</span> <span class="o">&lt;-</span><span class="n">time</span><span class="o">.</span><span class="n">After</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">Second</span> <span class="o">*</span> <span class="m">10</span><span class="p">)</span><span class="o">:</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"10 seconds elapsed and long running task didn't finish, exit</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="waitgroup">WaitGroup</h2>

<p>Para esperar a que finalicen múltiples <em>goroutines</em> se utiliza el objeto
<em>WaitGroup</em>.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"fmt"</span>
    <span class="s">"sync"</span>
    <span class="s">"time"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">long_running_task</span><span class="p">(</span><span class="n">wg</span> <span class="o">*</span><span class="n">sync</span><span class="o">.</span><span class="n">WaitGroup</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">time</span><span class="o">.</span><span class="n">Sleep</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">Second</span>  <span class="o">*</span> <span class="m">3</span><span class="p">)</span>
    <span class="n">wg</span><span class="o">.</span><span class="n">Done</span><span class="p">()</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">var</span> <span class="n">wg</span> <span class="n">sync</span><span class="o">.</span><span class="n">WaitGroup</span>
    <span class="k">const</span> <span class="n">numTasks</span> <span class="o">=</span> <span class="m">5</span>
    <span class="n">wg</span><span class="o">.</span><span class="n">Add</span><span class="p">(</span><span class="n">numTasks</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">numTasks</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
        <span class="k">go</span> <span class="n">long_running_task</span><span class="p">(</span><span class="o">&amp;</span><span class="n">wg</span><span class="p">)</span>
    <span class="p">}</span>
    <span class="n">wg</span><span class="o">.</span><span class="n">Wait</span><span class="p">()</span>

    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Finish"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="workers-pool">Workers pool</h2>

<p>Para terminar con la concurrencia vamos a implementar un patrón bastante común
que es un <em>worker pool</em>. Una cola de workers que aceptan tareas para ejecutarse
de forma concurrente.</p>

<p>La idea es usar <em>channels</em> para ir enviando tareas a los workers y otro canal
para capturar el resultado. Cuando no haya más tareas, se cierra el canal con
<em>close</em>.</p>

<p>Hay que tener en cuenta que el tamaño de los canales debe ser igual al
número de tareas a ejecutar para evitar deadlocks, ya que de lo contrario un
podría ocurrir que el hilo principal se bloquee porque no hay más espacio en el
canal para enviar un job y  la <em>goroutine</em> se bloquee porque no se está
desencolando los resultados desde el hilo principal.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"fmt"</span>
    <span class="s">"time"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">worker</span><span class="p">(</span><span class="n">id</span> <span class="kt">int</span><span class="p">,</span> <span class="n">job</span> <span class="o">&lt;-</span><span class="k">chan</span> <span class="kt">int</span><span class="p">,</span> <span class="n">result</span> <span class="k">chan</span><span class="o">&lt;-</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="k">range</span> <span class="n">job</span> <span class="p">{</span>
        <span class="n">time</span><span class="o">.</span><span class="n">Sleep</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">Second</span> <span class="o">*</span> <span class="m">1</span><span class="p">)</span>
        <span class="n">result</span> <span class="o">&lt;-</span> <span class="n">id</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">const</span> <span class="n">MAX_WORKERS</span> <span class="o">=</span> <span class="m">5</span>
    <span class="k">const</span> <span class="n">MAX_TASKS</span> <span class="o">=</span> <span class="m">20</span>
    
    <span class="n">job</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">int</span><span class="p">,</span> <span class="n">MAX_TASKS</span><span class="p">)</span>
    <span class="n">result</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">int</span><span class="p">,</span> <span class="n">MAX_TASKS</span><span class="p">)</span>

    <span class="c">//Launch the workers</span>
    <span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">MAX_WORKERS</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
        <span class="c">//Each worker will wait until a job is received</span>
        <span class="k">go</span> <span class="n">worker</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">job</span><span class="p">,</span> <span class="n">result</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="c">//Send job to workers</span>
    <span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">MAX_TASKS</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
        <span class="c">//Just send something to unblock the worker</span>
        <span class="c">//this could be the input for the worker</span>
        <span class="n">job</span> <span class="o">&lt;-</span> <span class="m">0</span>
    <span class="p">}</span>

    <span class="c">//Wait all result</span>
    <span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">MAX_TASKS</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
        <span class="n">id</span> <span class="o">:=</span> <span class="o">&lt;-</span> <span class="n">result</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Worker[%d] finished</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">id</span><span class="p">)</span>
    <span class="p">}</span>
    <span class="c">//close the job channel to unblock the goroutine</span>
    <span class="nb">close</span><span class="p">(</span><span class="n">job</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="links">Links</h2>

<p><a href="https://go.dev/doc/effective_go">Effective Go</a></p>

<p><a href="https://gobyexample.com/">Go by examples</a></p>]]></content><author><name>Andres</name></author><category term="Go" /><category term="Desarrollo" /><category term="dev" /></entry><entry><title type="html">Go parte 1 - structs, functions, methods, pointers, interfaces</title><link href="http://hardfloat.es//blog/2023/05/08/go-parte1.html" rel="alternate" type="text/html" title="Go parte 1 - structs, functions, methods, pointers, interfaces" /><published>2023-05-08T00:00:00-05:00</published><updated>2023-05-08T00:00:00-05:00</updated><id>http://hardfloat.es//blog/2023/05/08/go-parte1</id><content type="html" xml:base="http://hardfloat.es//blog/2023/05/08/go-parte1.html"><![CDATA[<ul id="markdown-toc">
  <li><a href="#introducción" id="markdown-toc-introducción">Introducción</a></li>
  <li><a href="#instalación" id="markdown-toc-instalación">Instalación</a></li>
  <li><a href="#clásico-hola-mundo" id="markdown-toc-clásico-hola-mundo">Clásico Hola Mundo</a></li>
  <li><a href="#tipos-primitivos" id="markdown-toc-tipos-primitivos">Tipos primitivos</a></li>
  <li><a href="#variables" id="markdown-toc-variables">Variables</a>    <ul>
      <li><a href="#inicialización" id="markdown-toc-inicialización">Inicialización</a></li>
      <li><a href="#valor-inicial" id="markdown-toc-valor-inicial">Valor inicial</a></li>
      <li><a href="#conversión-de-tipos" id="markdown-toc-conversión-de-tipos">Conversión de tipos</a></li>
      <li><a href="#constantes" id="markdown-toc-constantes">Constantes</a></li>
      <li><a href="#reserva-de-memoria-con-new" id="markdown-toc-reserva-de-memoria-con-new">Reserva de memoria con new</a></li>
    </ul>
  </li>
  <li><a href="#funciones" id="markdown-toc-funciones">Funciones</a>    <ul>
      <li><a href="#named-return-values" id="markdown-toc-named-return-values">Named return values</a></li>
      <li><a href="#punteros-y-funciones" id="markdown-toc-punteros-y-funciones">Punteros y funciones</a></li>
      <li><a href="#funciones-variádicas" id="markdown-toc-funciones-variádicas">Funciones variádicas</a></li>
      <li><a href="#closures" id="markdown-toc-closures">Closures</a></li>
    </ul>
  </li>
  <li><a href="#control-de-flujo" id="markdown-toc-control-de-flujo">Control de flujo</a>    <ul>
      <li><a href="#ifelse-for-switch" id="markdown-toc-ifelse-for-switch">if/else, for, switch</a></li>
      <li><a href="#defer" id="markdown-toc-defer">Defer</a></li>
    </ul>
  </li>
  <li><a href="#arrays" id="markdown-toc-arrays">Arrays</a></li>
  <li><a href="#slices" id="markdown-toc-slices">Slices</a>    <ul>
      <li><a href="#make-vs-new" id="markdown-toc-make-vs-new">make vs new</a></li>
    </ul>
  </li>
  <li><a href="#maps" id="markdown-toc-maps">Maps</a></li>
  <li><a href="#structs" id="markdown-toc-structs">Structs</a>    <ul>
      <li><a href="#struct-embedding" id="markdown-toc-struct-embedding">Struct embedding</a></li>
    </ul>
  </li>
  <li><a href="#métodos" id="markdown-toc-métodos">Métodos</a></li>
  <li><a href="#interfaces" id="markdown-toc-interfaces">Interfaces</a></li>
  <li><a href="#errors" id="markdown-toc-errors">Errors</a></li>
</ul>

<p>Como tengo que aprender el lenguaje <a href="https://go.dev/">Go</a> voy a comenzar una
serie hablando sobre el lenguaje y el camino del aprendizaje. Esto no va a ser
una guía o un tutorial sino una pequeña guía de consulta para mi mismo en el
futuro.</p>

<h2 id="introducción">Introducción</h2>

<p>Go es uno de los lenguajes <em>modernos</em> que forman parte de los lenguajes de moda
del momento. Entre las características que tiene son:</p>

<ul>
  <li>Multiparadigma.</li>
  <li>Estáticamente tipado (aunque posee inferencia de tipos).</li>
  <li>Lenguaje compilado y diseñado para ser compilado para diferentes plataformas
de forma sencilla.</li>
  <li>Posee recolector de basura por lo que la gestión de la memoria es automática.</li>
</ul>

<p>La filosofía del diseño es tener un lenguaje sencillo, compilación rápida,
primitivas de concurrencia en el propio lenguaje, posee un gestor de paquetes
propio y la propia toolchain ofrece las herramientas necesarias para las tareas
comunes en el desarrollo de software como testing, formato de código, gestión de
dependencias, compilador, depurador etc.</p>

<p>Cada nuevo lenguaje que aprendes es una oportunidad para aprender diferentes
filosofías de desarrollo y aprender nuevas técnicas. El lenguaje en sí tiene sus
pros y sus contras (¿Qué tecnología no las tiene?) entre los pros considero un
acierto tener las herramientas básicas como testing, formateo de código y
gestión de dependencias incorporado al lenguaje, la integración de todo esto es
más cómodo de trabajar. No tengo suficiente experiencia todavía en el mundo real
para destacar los contras, no obstante lo que me pesa al trabajar es no tener
ciertas cosas que encuentras en otros lenguajes orientados a objetos clásicos,
como por ejemplo poder contar con establecer variables públicas y privadas en un
objeto (En Go esto no se puede hacer directamente, tienes que jugar con la
visibilidad de los paquetes), el uso de mayúsculas para exportar variables,
objetos y funciones al consumidor (No es algo dramático pero al principio te
parece incómodo).</p>

<p>En definitiva es un lenguaje usado en el mundo real, con demanda y se han
realizado proyectos de envergadura con el, como por ejemplo Docker y Kubernetes
entre otros. Es un lenguaje productivo con multitud de librerías y
herramientas que te permiten desarrollar rápido y con calidad.</p>

<h2 id="instalación">Instalación</h2>

<p>La instalación depende de la plataforma en la que vayas a desarrollar. Aquí está
el link con las instrucciones:
<a href="https://go.dev/doc/install">https://go.dev/doc/install</a></p>

<h2 id="clásico-hola-mundo">Clásico Hola Mundo</h2>

<p>El clásico hola mundo en Go:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Hello world</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Para ejecutar directamente</span>
go run hello.go
<span class="c"># Para generar un ejecutable</span>
go build hello.go
<span class="c"># Y genera un ejecutable en el directorio de trabajo llamado hello</span>
</code></pre></div></div>

<p>Cada programa en Go está hecho de <em>packages</em> en este caso hemos llamado a
nuestro paquete <em>main</em>. El punto de entada del programa es la función main.</p>

<h2 id="tipos-primitivos">Tipos primitivos</h2>

<p>Los tipos primitivos son:</p>

<ul>
  <li>bool</li>
  <li>string</li>
  <li>int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64</li>
  <li>byte (Alias de uint8)</li>
  <li>float32, float64</li>
  <li>complex64, complex128</li>
  <li>rune (Alias de int32)</li>
  <li>arrays</li>
  <li>maps</li>
  <li>slices</li>
</ul>

<p>Go posee punteros y se representan con los mismos símbolos y poseen el mismo
significado que en lenguajes como C/C++.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">number</span> <span class="o">:=</span> <span class="m">32</span>
<span class="n">p</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="n">number</span> <span class="c">//Puntero a number</span>

<span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="m">50</span> <span class="c">//Modifica el valor de number a través del puntero</span>
</code></pre></div></div>

<h2 id="variables">Variables</h2>

<h3 id="inicialización">Inicialización</h3>

<p>La sintaxis de la declaración de variables en Go es diferente a lenguajes como C
y C++. El tipo de la variable siempre va al final.</p>

<p>No es necesario declarar el tipo de las variables, en Go existen inferencias de
tipos, es decir el tipo de la variable se infiere en función del tipo de la
variable/constante del lado derecho.</p>

<p>Por defecto las variables se declaran en el stack, para declarar variables en el
<em>heap</em> es necesario new. Pero lo veremos más adelante</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">var</span> <span class="n">counter</span> <span class="kt">int</span> <span class="c">//Declaración de variable</span>
    <span class="k">var</span> <span class="n">index</span> <span class="kt">int</span> <span class="o">=</span> <span class="m">0</span> <span class="c">//Declaración e inicialización</span>
    <span class="c">//Inferencia de tipos</span>
    <span class="n">j</span> <span class="o">:=</span> <span class="n">index</span> <span class="c">//j es de tipo int porque la variable index es de tipo int</span>
    <span class="n">message</span> <span class="o">:=</span> <span class="s">"Hello world"</span> <span class="c">//message es de tipo string</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="valor-inicial">Valor inicial</h3>

<p>Cuando se omite el valor de inicialización las variables se inicializan a cero
para el caso de enteros, false para booleanos y cadenas vacías “” para strings.</p>

<h3 id="conversión-de-tipos">Conversión de tipos</h3>

<p>La conversión de tipos explícita está prohibida en Go. Al hacer eso el programa
no compila. La conversión de tipos debe ser explícita:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">pi</span> <span class="o">:=</span> <span class="m">3.1416</span>
    <span class="n">pi_int</span> <span class="o">:=</span> <span class="kt">int</span><span class="p">(</span><span class="n">pi</span><span class="p">)</span> <span class="c">//conversión explicita obtiene el valor entero</span>

    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"pi_int=%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pi_int</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="constantes">Constantes</h3>

<p>Las constantes se declaran con la palabra clave <strong>const</strong>. Las constantes no se
puede declarar con la sintaxis :=</p>

<p>Los tipos que pueden constantes son: string, bool y tipos numéricos.</p>

<p>Otra sintaxis de declarar constantes es:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">const</span> <span class="p">(</span>
    <span class="n">PI</span> <span class="o">=</span> <span class="m">3.1416</span>
    <span class="n">E</span> <span class="o">=</span> <span class="m">2.71828</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">const</span> <span class="n">MY_CONSTANT</span> <span class="o">=</span>  <span class="m">7</span><span class="c">//sintaxis clásica</span>

    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"pi=%f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">PI</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="reserva-de-memoria-con-new">Reserva de memoria con new</h3>

<p>Podemos declarar variables en memoria dinámica usando la función <em>new</em>. Al
reservar memoria con new los bloques de memoria se inicializan al valor cero.
Esto implica que cuando usemos objetos hay que tener en cuenta la inicialización
de los miembros. No obstante no es necesario hacerlo manualmente al estilo de C
(memset + inicialización de cada miembro al valor deseado) el lenguaje provee de
sintaxis para reservar memoria dinámica y darle un valor por defecto como si de
un constructor se tratara.</p>

<p>Recordar que Go tiene un recolector de basura y no es necesario eliminar la
memoria de forma manual.</p>

<h2 id="funciones">Funciones</h2>

<p>Las funciones son otro tipo primitivo en Go. Las funciones pueden devolver
múltiples valores, devolver otras funciones, etc.</p>

<p>No existe la sobrecarga en las funciones, cada función debe tener un nombre
único</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">func</span> <span class="n">add</span><span class="p">(</span><span class="n">a</span> <span class="kt">int</span><span class="p">,</span> <span class="n">b</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">swap</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="kt">int</span><span class="p">)</span> <span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">y</span><span class="p">,</span> <span class="n">x</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"add(1, 1)=%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">add</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">1</span><span class="p">))</span>

    <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">:=</span> <span class="n">swap</span><span class="p">(</span><span class="m">3</span><span class="p">,</span> <span class="m">5</span><span class="p">)</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"swap(3, 5)=%d,%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="named-return-values">Named return values</h3>

<p>Go retorna valores de las funciones por el nombre. Un return sin argumentos usa
el nombre los argumentos de salida para retornar el valor. Mejor un ejemplo:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">func</span> <span class="n">swap</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="kt">int</span><span class="p">)</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">b</span>
    <span class="n">y</span> <span class="o">=</span> <span class="n">a</span>
    <span class="k">return</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">a</span> <span class="o">:=</span> <span class="m">5</span>
    <span class="n">b</span> <span class="o">:=</span> <span class="m">3</span>
    <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">:=</span> <span class="n">swap</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"swap(%d, %d)=%d,%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="punteros-y-funciones">Punteros y funciones</h3>

<p>Las funciones pueden recibir punteros a tipos de datos. El comportamiento se
similar a C/C++ cuando se pasa una variable por valor la función recibe una
copia de la variable y cuando se pasa un puntero no se realiza una copia.
Modificar una variable con un puntero modifica la variable global.</p>

<p>Destacar que a nivel de funciones Go es sensible a si una variable se pasa por
valor o por referencia, es decir si una función espera una referencia (variable
pasada por puntero) y se le pasa por valor da un error de compilación.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">func</span> <span class="n">foo</span><span class="p">(</span><span class="n">p</span> <span class="o">*</span><span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
    <span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="o">*</span><span class="n">p</span> <span class="o">*</span> <span class="m">10</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">n</span> <span class="o">:=</span> <span class="m">1</span>
    <span class="n">foo</span><span class="p">(</span><span class="o">&amp;</span><span class="n">n</span><span class="p">)</span> <span class="c">//OK</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"n=%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span>

    <span class="n">j</span> <span class="o">:=</span> <span class="m">2</span>
    <span class="n">foo</span><span class="p">(</span><span class="n">j</span><span class="p">)</span> <span class="c">//ERROR de compilacion</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Recordar que esta sensibilidad entre pasar por valor o referencia solo ocurre en
funciones</strong></p>

<h3 id="funciones-variádicas">Funciones variádicas</h3>

<p>Las funciones variádicas son funciones que aceptan cualquier número de
parámetros. La sintaxis es la siguiente:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">func</span> <span class="n">sum</span><span class="p">(</span><span class="n">nums</span> <span class="o">...</span><span class="kt">int</span><span class="p">)</span> <span class="p">(</span><span class="n">total</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">total</span> <span class="o">=</span> <span class="m">0</span>
    <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">num</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">nums</span> <span class="p">{</span>
        <span class="n">total</span> <span class="o">+=</span> <span class="n">num</span>
    <span class="p">}</span>
    <span class="k">return</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">total</span> <span class="o">:=</span> <span class="n">sum</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">)</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"total=%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">total</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="closures">Closures</h3>

<p>Go soporta el uso de funciones anónimas lo que pueden formar <em>closures</em></p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">func</span> <span class="n">incrementer</span><span class="p">(</span><span class="n">step</span> <span class="kt">int</span><span class="p">)</span> <span class="k">func</span><span class="p">()</span> <span class="kt">int</span> <span class="p">{</span>
    <span class="n">counter</span> <span class="o">:=</span> <span class="m">0</span>
    <span class="k">return</span> <span class="k">func</span><span class="p">()</span> <span class="kt">int</span> <span class="p">{</span>
        <span class="n">counter</span> <span class="o">+=</span> <span class="n">step</span>
        <span class="k">return</span> <span class="n">counter</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">inc</span> <span class="o">:=</span> <span class="n">incrementer</span><span class="p">(</span><span class="m">1</span><span class="p">)</span>
    <span class="n">inc</span><span class="p">()</span>
    
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">inc</span><span class="p">())</span> <span class="c">//should print 2</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="control-de-flujo">Control de flujo</h2>

<h3 id="ifelse-for-switch">if/else, for, switch</h3>

<p>La sintaxis de los ifs y for son similares a C/C++ pero sin paréntesis. No
existen los <em>whiles</em> en Go, en su lugar se usan for sin condición de parada.</p>

<p>Go posee sentencias <em>switch</em> a diferencia de C/C++ los <em>switch</em> en Go <strong>solo
ejecutan el caso seleccionado e ignora los que vienen a continuación</strong>. El orden
de evaluación es desde arriba hacia abajo (<em>from top to bottom</em>)</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="m">5</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span>
    <span class="p">}</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>

    <span class="n">max</span> <span class="o">:=</span> <span class="m">10</span>
    <span class="k">if</span> <span class="n">max</span> <span class="o">&gt;=</span> <span class="m">10</span> <span class="p">{</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"max &gt;= 10</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="n">platform</span> <span class="o">:=</span> <span class="s">"linux"</span>
    <span class="k">switch</span> <span class="n">platform</span> <span class="p">{</span>
    <span class="k">case</span> <span class="s">"linux"</span><span class="o">:</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Linux platform</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
    <span class="k">case</span> <span class="s">"lindows"</span><span class="o">:</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Window platform</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
    <span class="k">case</span> <span class="s">"MacOs"</span><span class="o">:</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"MacOs platform</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
    <span class="k">default</span><span class="o">:</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Unknow platform</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="defer">Defer</h3>

<p>La sentencia defer retrasa la ejecución de una función hasta que la función
actual haya salido del scope. Los defer se pueden apilar, es decir, puedes
llamar múltiples veces un defer y se ejecutaran en orden LIFO (Last In, First
out).</p>

<p>Los defers son bastantes útiles para cerrar recursos y quedan bastante legibles
en el código.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"counting"</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="m">10</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
        <span class="k">defer</span> <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
    <span class="p">}</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"done"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="arrays">Arrays</h2>

<p>Los arrays son una secuencia de datos.</p>

<p>Destacar una vez más que los arrays son de tamaño fijo y una vez declarados si
tamaño no varía. Los arrays se declaran en memoria estática no se reserva
memoria para ellos.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">number_list</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">int</span><span class="p">{</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">4</span><span class="p">}</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"number_list len=%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">number_list</span><span class="p">))</span>
    <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">value</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">number_list</span> <span class="p">{</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Destacar la palabra clave <em>range</em> que nos permite poder iterar con secuencia de
datos. <em>range</em> devuelve siempre dos argumentos: índice y valor. Para ignorar
cualesquiera de los valores devueltos hay que usar <em>_</em> para que el compilador de
Go entienda que no vamos a usar esa variable.</p>

<h2 id="slices">Slices</h2>

<p>Los arrays en realidad son el bloque de construcción de los
slices que es lo que se usará en la práctica. Los slices usan memoria dinámicas
y pueden variar su tamaño. Además tenemos los slices mantienen información de su
tamaño que se puede consultar con la función <em>len</em>.</p>

<p>Para crear una slice de cualquier tipo se usa la función <em>make</em>. Esta función
reserva memoria y ademas inicialia los valores de la estructura interna de los
slices.</p>

<p>Para obtener subelementos de un slice la sintaxis es igual que la que se usa en
python.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">func</span> <span class="n">print_elements</span><span class="p">(</span><span class="n">s</span> <span class="p">[]</span><span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"number_list len=%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">))</span>
    <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">v</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">s</span> <span class="p">{</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">number_list</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>
    <span class="n">print_elements</span><span class="p">(</span><span class="n">number_list</span><span class="p">)</span>

    <span class="c">//print subelements</span>
    <span class="n">print_elements</span><span class="p">(</span><span class="n">number_list</span><span class="p">[</span><span class="m">0</span><span class="o">:</span> <span class="m">5</span><span class="p">])</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="make-vs-new">make vs new</h3>

<p>Existen dos funciones para reservar memoria: <em>make</em> y <em>new. La realidad es que
ambas funciones tiene propósitos diferentes, *new</em> reserva e inicializa la memoria
a cero mientras que <em>make</em> está pensada para reservar memoria para slices, maps
y channels. La función <em>make</em> además de reservar memoria inicializa las
variables internas de dichas estructuras de datos a los valores
correspondientes.</p>

<p>La regla de oro es:</p>

<blockquote>
  <p>Usar make para slices, maps y channels y new para valors numéricos, structs etc.</p>
</blockquote>

<h2 id="maps">Maps</h2>

<p>Los mapas son estructuras de datos clave/valor. Los mapas se construyen con
make.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">city_capitals</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">string</span><span class="p">)</span>
    
    <span class="c">//Insert element</span>
    <span class="n">city_capitals</span><span class="p">[</span><span class="s">"Spain"</span><span class="p">]</span> <span class="o">=</span> <span class="s">"Madrid"</span>
    <span class="n">city_capitals</span><span class="p">[</span><span class="s">"Portugal"</span><span class="p">]</span> <span class="o">=</span> <span class="s">"Lisboa"</span>
    <span class="n">city_capitals</span><span class="p">[</span><span class="s">"France"</span><span class="p">]</span> <span class="o">=</span> <span class="s">"Paris"</span>
    <span class="n">city_capitals</span><span class="p">[</span><span class="s">"Israel"</span><span class="p">]</span> <span class="o">=</span> <span class="s">"Tel Aviv"</span>

    <span class="c">//Delete element</span>
    <span class="nb">delete</span><span class="p">(</span><span class="n">city_capitals</span><span class="p">,</span> <span class="s">"Israel"</span><span class="p">)</span>
    <span class="n">city_capitals</span><span class="p">[</span><span class="s">"Israel"</span><span class="p">]</span> <span class="o">=</span> <span class="s">"Palestina"</span>

    <span class="c">//Test if element is present</span>
    <span class="n">palestina_capital</span><span class="p">,</span> <span class="n">ok</span> <span class="o">:=</span> <span class="n">city_capitals</span><span class="p">[</span><span class="s">"Palestina"</span><span class="p">]</span>
    <span class="k">if</span> <span class="n">ok</span> <span class="p">{</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Palestina capital: %s"</span><span class="p">,</span> <span class="n">palestina_capital</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="c">//Retrieve element</span>
    <span class="n">spain_capital</span> <span class="o">:=</span> <span class="n">city_capitals</span><span class="p">[</span><span class="s">"Spain"</span><span class="p">]</span>
    <span class="k">if</span> <span class="n">spain_capital</span> <span class="o">!=</span> <span class="s">"Madrid"</span> <span class="p">{</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"What happended to Spain?</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="c">//Iterating with maps</span>
    <span class="c">//range returns key,value pair</span>
    <span class="k">for</span> <span class="n">country</span><span class="p">,</span> <span class="n">capital</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">city_capitals</span> <span class="p">{</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%s -&gt; %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">country</span><span class="p">,</span> <span class="n">capital</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="structs">Structs</h2>

<p>Las structs son agrupaciones de datos clásicas como podrían ser en lenguajes
como C/C++.</p>

<p>Los campos de una struct se acceden con un punto, independientemente de que sea
una variable declarada en el stack o un puntero a una struct. El lenguaje nos
permite tener una sintaxis única.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">type</span> <span class="n">Point</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="kt">int</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">print_point</span><span class="p">(</span><span class="n">p</span> <span class="o">*</span><span class="n">Point</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Point{x=%d,y=%d}</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="c">//Declaration syntax</span>
    <span class="k">var</span> <span class="n">point</span> <span class="n">Point</span> <span class="c">//all members set to zero</span>
    <span class="n">origin</span> <span class="o">:=</span> <span class="n">Point</span><span class="p">{</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">}</span>
    <span class="n">dest</span> <span class="o">:=</span> <span class="n">Point</span><span class="p">{</span><span class="n">x</span><span class="o">:</span> <span class="m">1</span><span class="p">,</span> <span class="n">y</span><span class="o">:</span> <span class="m">0</span><span class="p">}</span>

    <span class="n">point_in_heap</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="n">Point</span><span class="p">)</span>
    <span class="n">point_in_heap</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="m">2</span>
    <span class="n">point_in_heap</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="m">3</span>

    <span class="n">print_point</span><span class="p">(</span><span class="o">&amp;</span><span class="n">point</span><span class="p">)</span>
    <span class="n">print_point</span><span class="p">(</span><span class="o">&amp;</span><span class="n">origin</span><span class="p">)</span>
    <span class="n">print_point</span><span class="p">(</span><span class="o">&amp;</span><span class="n">dest</span><span class="p">)</span>
    <span class="n">print_point</span><span class="p">(</span><span class="n">point_in_heap</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="struct-embedding">Struct embedding</h3>

<p>Go soporta incrustar structs e interfaces que facilita la composición de tipos.
La sintaxis es:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">User</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">name</span> <span class="kt">string</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">Account</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">User</span> <span class="c">//Embedded struct, just include the type</span>
    <span class="n">email</span> <span class="kt">string</span>
    <span class="n">password</span> <span class="kt">string</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Como se observa, en la estructura <em>Account</em> el campo <em>User</em> se incluye solo
escribiendo el tipo y no se le asigna un nombre de variable. Esto permite
acceder al campo <em>name</em> directamente desde <em>Account</em> sin tener que pasar por la
variable intermedia. Veamos el ejemplo:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">//Initalize Account</span>
<span class="n">account</span> <span class="o">:=</span> <span class="n">Account</span><span class="p">{</span>
    <span class="n">User</span><span class="p">{</span><span class="s">"Andres"</span><span class="p">},</span>
    <span class="s">"andres@mail.com"</span><span class="p">,</span>
    <span class="s">"mypassword"</span>
<span class="p">}</span>
<span class="c">//Access to members</span>
<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"name=%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">account</span><span class="o">.</span><span class="n">name</span><span class="p">)</span> <span class="c">//Notice the direct access</span>
<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"email=%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">account</span><span class="o">.</span><span class="n">email</span><span class="p">)</span>
<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"password=%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">account</span><span class="o">.</span><span class="n">password</span><span class="p">)</span>
</code></pre></div></div>

<p><a href="https://gobyexample.com/struct-embedding">https://gobyexample.com/struct-embedding</a></p>

<h2 id="métodos">Métodos</h2>

<p>Go no posee clases pero podemos definir métodos para los tipos de datos. Esto en
combinación con structs (que no dejan de ser un tipo de datos en el fondo)
permiten poder aplicar los conceptos de programación orientada objetos. Al no
haber clases tampoco hay herencia, pero se puede resolver usando la composición
en lugar de la herencia, con lo cual podemos extender la funcionalidad sin
demasiados problemas.</p>

<p>Según el vocubulario de Go, un método es una función con un argumento especial
llamado *reciever argument**. Veamos el ejemplo anterior pero usando un método
para imprimir los campos de Point:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">type</span> <span class="n">Point</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="kt">int</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">p</span> <span class="o">*</span><span class="n">Point</span><span class="p">)</span> <span class="nb">print</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Point{x=%d,y=%d}</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">p</span> <span class="n">Point</span><span class="p">)</span> <span class="n">print_no_pointer</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Point{x=%d,y=%d}</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">origin</span> <span class="o">:=</span> <span class="n">Point</span><span class="p">{</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">}</span>
    <span class="n">origin</span><span class="o">.</span><span class="nb">print</span><span class="p">()</span> <span class="c">//method call</span>
    <span class="n">origin</span><span class="o">.</span><span class="n">print_no_pointer</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Aplican las mismas normas de paso por valor o por referencia. Si se pasa por
valor, el método recibirá una copia de la variable mientras que en un puntero
no, y tiene la posibilida de modificar el <em>receiver</em>.</p>

<p>Destacar que en el caso de los métodos si que pueden existir dos métodos de
diferente tipo con el mismo nombre.</p>

<h2 id="interfaces">Interfaces</h2>

<p>Go provee de la capacidad de crear interfaces. Es decir, la capacidad de crear
contratos entre structs para que implementen una conjunto de funciones comunes
que satisfagan la interfaz (el contrato).</p>

<p>Siempre que una struct implemente todos los métodos definidos por una interfaz,
se considera que el contrato se cumple. Si no lo hace y se trata de usar una
struct que no implemente todas las funciones, da un error de compilación.</p>

<p>Esta parte es la definición normal de una interfaz, no obstante no existe una
relación explícita en el código de que una struct implemente tal interfaz. Me
parece algo peculiar.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="s">"fmt"</span>

<span class="c">//Cat</span>
<span class="k">type</span> <span class="n">Cat</span> <span class="k">struct</span> <span class="p">{}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">Cat</span><span class="p">)</span> <span class="n">Eat</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Cat::Eat</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="p">}</span>

<span class="c">//Dog</span>
<span class="k">type</span> <span class="n">Dog</span> <span class="k">struct</span> <span class="p">{}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">d</span> <span class="o">*</span><span class="n">Dog</span><span class="p">)</span> <span class="n">Eat</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Dog::Eat</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="p">}</span>

<span class="c">//Tree, doesn't follow Animal interface</span>
<span class="k">type</span> <span class="n">Tree</span> <span class="k">struct</span> <span class="p">{}</span>

<span class="c">//Interface</span>
<span class="k">type</span> <span class="n">Animal</span> <span class="k">interface</span> <span class="p">{</span>
    <span class="n">Eat</span><span class="p">()</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">AnimalEat</span><span class="p">(</span><span class="n">animal</span> <span class="n">Animal</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">animal</span><span class="o">.</span><span class="n">Eat</span><span class="p">()</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">cat</span> <span class="o">:=</span> <span class="n">Cat</span><span class="p">{}</span>
    <span class="n">dog</span> <span class="o">:=</span> <span class="n">Dog</span><span class="p">{}</span>
    <span class="n">tree</span> <span class="o">:=</span> <span class="n">Tree</span><span class="p">{}</span>

    <span class="n">AnimalEat</span><span class="p">(</span><span class="o">&amp;</span><span class="n">cat</span><span class="p">)</span>
    <span class="n">AnimalEat</span><span class="p">(</span><span class="o">&amp;</span><span class="n">dog</span><span class="p">)</span>
    <span class="n">AnimalEat</span><span class="p">(</span><span class="o">&amp;</span><span class="n">tree</span><span class="p">)</span> <span class="c">//Tree doesn't follow animal interface, so go throws compiler error</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="errors">Errors</h2>

<p>En Go un error es una interfaz que cumple este contrato:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="kt">error</span> <span class="k">interface</span> <span class="p">{</span>
    <span class="n">Error</span><span class="p">()</span> <span class="kt">string</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Todos las strucst que cumplan este contrato se pueden devolver como el tipo
error.</p>]]></content><author><name>Andres</name></author><category term="Go" /><category term="Desarrollo" /><category term="dev" /></entry><entry><title type="html">Mejora tus tests con funciones identidad</title><link href="http://hardfloat.es//blog/2023/04/06/mejora-tus-tests-con-funciones-identidad.html" rel="alternate" type="text/html" title="Mejora tus tests con funciones identidad" /><published>2023-04-06T00:00:00-05:00</published><updated>2023-04-06T00:00:00-05:00</updated><id>http://hardfloat.es//blog/2023/04/06/mejora-tus-tests-con-funciones-identidad</id><content type="html" xml:base="http://hardfloat.es//blog/2023/04/06/mejora-tus-tests-con-funciones-identidad.html"><![CDATA[<p>Una función identidad es una función que devuelve el mismo valor que recibe por
parámetro.</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">f</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">x</span>
<span class="p">}</span>
</code></pre></div></div>

<p>En algunas circunstancias puede ser útil para mejorar la legibilidad del código,
sobre todo si estamos haciendo refactoring y no pretendemos hacer grandes
cambios.</p>

<p>Consideremos el siguiente caso. Imagina que tenemos una aplicación que realiza
peticiones HTTP y mantiene estádisticas de número de peticiones satisfactorias,
número de peticiones fallidas. En el código de test existe una función que se
encarga de hacer esos chequeos:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kr">inline</span> <span class="kt">void</span> <span class="nf">assert_http_statistics</span><span class="p">(</span><span class="n">HttpRequest</span><span class="o">&amp;</span> <span class="n">http_req</span><span class="p">,</span> <span class="kt">int</span> <span class="n">num_success</span><span class="p">,</span> <span class="kt">int</span> <span class="n">num_failures</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">EXPECT_EQ</span><span class="p">(</span><span class="n">http_req</span><span class="p">.</span><span class="n">get_num_success_requests</span><span class="p">(),</span> <span class="n">num_success</span><span class="p">);</span>
    <span class="n">EXPECT_EQ</span><span class="p">(</span><span class="n">http_req</span><span class="p">.</span><span class="n">get_num_failures_request</span><span class="p">(),</span> <span class="n">num_failures</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">TEST</span><span class="p">(</span><span class="n">HttpRequestTest</span><span class="p">,</span> <span class="n">check_http_requests_statistics</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">HttpRequest</span> <span class="n">http_req</span><span class="p">;</span>
    <span class="c1">//Success http request</span>
    <span class="n">http_req</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"https://hardfloat.es"</span><span class="p">);</span>
    <span class="c1">//Failed http request</span>
    <span class="n">http_req</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"https://dsugerreasadasc.io"</span><span class="p">);</span>

    <span class="n">assert_http_statistics</span><span class="p">(</span><span class="n">http_req</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Al pasarle dos enteros a la función <em>http_requests_statistics</em> se pierde
legibilidad porque es necesario consultar qué significan esos dos parámetros, si
usamos funciones identidad veamos como queda.</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kt">int</span> <span class="nf">num_http_success_requests</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">x</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">num_http_failed_requests</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">x</span><span class="p">;</span>
<span class="p">}</span>

<span class="kr">inline</span> <span class="kt">void</span> <span class="n">assert_http_statistics</span><span class="p">(</span><span class="n">HttpRequest</span><span class="o">&amp;</span> <span class="n">http_req</span><span class="p">,</span> <span class="kt">int</span> <span class="n">num_success</span><span class="p">,</span> <span class="kt">int</span> <span class="n">num_failures</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">EXPECT_EQ</span><span class="p">(</span><span class="n">http_req</span><span class="p">.</span><span class="n">get_num_success_requests</span><span class="p">(),</span> <span class="n">num_success</span><span class="p">);</span>
    <span class="n">EXPECT_EQ</span><span class="p">(</span><span class="n">http_req</span><span class="p">.</span><span class="n">get_num_failures_request</span><span class="p">(),</span> <span class="n">num_failures</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">TEST</span><span class="p">(</span><span class="n">HttpRequestTest</span><span class="p">,</span> <span class="n">check_http_requests_statistics</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">HttpRequest</span> <span class="n">http_req</span><span class="p">;</span>
    <span class="c1">//Success http request</span>
    <span class="n">http_req</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"https://hardfloat.es"</span><span class="p">);</span>
    <span class="c1">//Failed http request</span>
    <span class="n">http_req</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"https://dsugerreasadasc.io"</span><span class="p">);</span>

    <span class="n">assert_http_statistics</span><span class="p">(</span><span class="n">http_req</span><span class="p">,</span> 
                           <span class="n">num_http_success_requests</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span>
                           <span class="n">num_http_failed_requests</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Esta es una forma rápida de mejorar la legibilidad del código que no nos cuesta
nada y a la larga lo agradeceremos.</p>]]></content><author><name>Andres</name></author><category term="Testing" /><category term="Desarrollo" /><category term="Dev" /><summary type="html"><![CDATA[Una función identidad es una función que devuelve el mismo valor que recibe por parámetro.]]></summary></entry><entry><title type="html">Depuración con GDB</title><link href="http://hardfloat.es//blog/2023/04/03/depuracion-con-gdb.html" rel="alternate" type="text/html" title="Depuración con GDB" /><published>2023-04-03T00:00:00-05:00</published><updated>2023-04-03T00:00:00-05:00</updated><id>http://hardfloat.es//blog/2023/04/03/depuracion-con-gdb</id><content type="html" xml:base="http://hardfloat.es//blog/2023/04/03/depuracion-con-gdb.html"><![CDATA[<p>Hoy toca hablar sobre GDB el depurador estándar del compilador GNU. Normalmente
los IDEs suelen integrar una interfaz gráfica para interactuar con los
<strong>debuggers</strong> de cada lenguaje y no suele ser necesario aprender a usar un
<em>debugger</em> por consola. Pero como siempre pasa, cuando necesitas ese
conocimiento suele ser demasiado tarde y te arrepientes de tu dependencia a los
entornos de desarrollo modernos. En cualquier caso aprender a usar GDB por
consola te permite poder integrarlo en prácticamente en cualquier entorno de
desarrollo.</p>

<p>Normalmente los casos de usos de un depurador suele ser para:</p>

<ul>
  <li>Abrir un core y hacer un backtrace para ver las últimas llamadas a funciones
antes del crash.</li>
  <li>Lanzar un programa a ir yendo paso a paso por el progama para poder ir
imprimiendo el valor de las variables y las funciones por las que pasa.</li>
</ul>

<h2 id="opciones-del-compilador">Opciones del compilador</h2>

<p>Para poder usar GDB es necesario compilar el software habilitando las símbolos
de depuración. En GDB suele ser con el flag -g. También seria conveniente
deshabilitar las optimizaciones del compilador para que no omita ciertas
variables y no se puendan mostrar en GSB, no obstante esto último puede ser
opcional.</p>

<p>También merece la pena agregar -g3 para indicar al compilador que incluya la
información de depuración para las macros.</p>

<h2 id="gdb-básico">GDB básico</h2>

<p>Vamos con un ejemplo básico:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">add</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>y compilamos:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>g++ <span class="nt">-g</span> <span class="nt">-Wall</span> <span class="nt">-std</span><span class="o">=</span>c++20 <span class="nt">-g3</span> <span class="nt">-O0</span> main.cc <span class="nt">-o</span> main.out
</code></pre></div></div>

<p>Para lanzar gdb</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gdb &lt;executable&gt;
</code></pre></div></div>

<h3 id="gdb-con-argumentos">GDB con argumentos</h3>

<p>Normalmente la mayoría de aplicaciones requieren una serie de argumentos que se
le pasan por consola. Para poder depurar aplicaciones con argumentos se lanza
gdb con el flag –args. Modifiquemos el programa anterior para aceptar
argumentos por cli:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">add</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">argc</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Usage "</span> <span class="o">&lt;&lt;</span> <span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
                  <span class="o">&lt;&lt;</span> <span class="s">" num1 num2"</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
        <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="n">stoi</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
    <span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="n">stoi</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"add("</span> <span class="o">&lt;&lt;</span> <span class="n">a</span> <span class="o">&lt;&lt;</span> <span class="s">","</span> <span class="o">&lt;&lt;</span> <span class="n">b</span> <span class="o">&lt;&lt;</span> <span class="s">")="</span>
        <span class="o">&lt;&lt;</span> <span class="n">add</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gdb <span class="nt">--args</span> &lt;executable&gt; &lt;arg1&gt; &lt;arg2&gt; ... &lt;argn&gt;
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gdb <span class="nt">--args</span> main 1 2
</code></pre></div></div>

<h3 id="abrir-un-core">Abrir un core</h3>

<p>Cuando un software termina con un crash por defecto en Linux no se genera el
fichero de core. Para poder habilitarlo hay que lanzar el comando ulimit.
Recordar esto para entornos de producción porque si se produce un core no vamos
a poder contar con esa valiosa información.</p>

<p>El fichero de core tiene el formato de: core.8721. El número que sigue a core es
el pid del ejecutable.</p>

<p>Tanto el formato del fichero del core como habilitar que se vuelque por defecto
se puede configurar escribiendo ciertos ficheros del kernel.</p>

<p>Por ejemplo, usemos el programa anterior abortando en la función add:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">add</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">abort</span><span class="p">();</span>
    <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">gdb</span> <span class="n">main</span> <span class="n">core</span><span class="mf">.123</span>
<span class="err">$</span> <span class="n">run</span>
<span class="n">program</span> <span class="n">received</span> <span class="n">signal</span> <span class="n">SIGABRT</span><span class="p">,</span> <span class="n">Aborted</span><span class="p">.</span>
<span class="n">__pthread_kill_implementation</span> <span class="p">(</span><span class="n">threadid</span><span class="o">=&lt;</span><span class="n">optimized</span> <span class="n">out</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">signo</span><span class="o">=</span><span class="n">signo</span><span class="err">@</span><span class="n">entry</span><span class="o">=</span><span class="mi">6</span><span class="p">,</span> <span class="n">no_tid</span><span class="o">=</span><span class="n">no_tid</span><span class="err">@</span><span class="n">entry</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span> <span class="n">at</span> <span class="n">pthread_kill</span><span class="p">.</span><span class="n">c</span><span class="o">:</span><span class="mi">44</span>
<span class="n">Downloading</span> <span class="n">source</span> <span class="n">file</span> <span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">src</span><span class="o">/</span><span class="n">debug</span><span class="o">/</span><span class="n">glibc</span><span class="o">/</span><span class="n">glibc</span><span class="o">/</span><span class="n">nptl</span><span class="o">/</span><span class="n">pthread_kill</span><span class="p">.</span><span class="n">c</span>
<span class="mi">44</span>            <span class="k">return</span> <span class="n">INTERNAL_SYSCALL_ERROR_P</span> <span class="p">(</span><span class="n">ret</span><span class="p">)</span> <span class="o">?</span> <span class="n">INTERNAL_SYSCALL_ERRNO</span> <span class="p">(</span><span class="n">ret</span><span class="p">)</span> <span class="o">:</span> <span class="mi">0</span><span class="p">;</span>
<span class="err">$</span> <span class="n">bt</span>
<span class="p">(</span><span class="n">gdb</span><span class="p">)</span> <span class="n">bt</span>
<span class="cp">#0  __pthread_kill_implementation (threadid=&lt;optimized out&gt;, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
#1  0x00007ffff7aa0953 in __pthread_kill_internal (signo=6, threadid=&lt;optimized out&gt;) at pthread_kill.c:78
#2  0x00007ffff7a51ea8 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#3  0x00007ffff7a3b53d in __GI_abort () at abort.c:79
#4  0x00005555555562bc in add (a=1, b=2) at main.cc:7
#5  0x000055555555646b in main (argc=3, argv=0x7fffffffdd48) at main.cc:21
</span></code></pre></div></div>

<p>Asi podemos abrir el core y conocer las últimas funciones que se ejecutaron.</p>

<h3 id="gdb-contra-un-proceso-en-ejecución">GDB contra un proceso en ejecución</h3>

<p>Otro uso interesante de GDB es que te permite poder acoplar el depurador en una
aplicación que está corriendo mediante el PID del proceso.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gdb <span class="nt">--pid</span> &lt;PID&gt;
</code></pre></div></div>

<h3 id="depuración-remota">Depuración remota</h3>

<p>También existe la posibilidad de depurar código de forma remota. Es decir, se
puede depurar código que está corriendo en una máquina A y desde una máquina B
depurar el código de forma remota.</p>

<p>Máquina remota</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gdbserver :&lt;PORT&gt; &lt;executable&gt; &lt;args&gt;
</code></pre></div></div>

<p>Máquina de trabajo</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gdb
target remote &lt;IP&gt;:&lt;port&gt;
</code></pre></div></div>

<h2 id="habilitar-interfaz-de-terminal-tui">Habilitar interfaz de terminal (tui)</h2>

<p>Cuando estemos frente a una sesión de depuración tener un interfaz de texto
exclusivamente se puede hacer un poco tedioso porque tenemos que ir lanzando el
comando <strong>list</strong> para mostrar el código fuente. Gdb posee una interfaz de
terminal que divide la pantalla entre una cli para comandos gdb y el código
fuente. Para habilitarlo:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gdb <span class="nt">--tui</span> &lt;executable&gt;
</code></pre></div></div>

<h2 id="scripting-con-gdb">Scripting con gdb</h2>

<p>Otro de las usos en los que me he encontrado es el de poder hacer scripting con
gdb. El caso en particular consistía en abrir una lista de ficheros de cores e
imprimir el resultado por pantalla para poder analizarlos, ordenarlos, etc.</p>

<p>Los flags para poder hacer scripting son:</p>

<ul>
  <li>–batch: Suprime texto de salida y sale con status 0 al terminar</li>
  <li>–ex <CMD>: Ejecuta el comando de GDB desado</CMD></li>
  <li>-x <FILE>: Especifica un fichero con una lista de comandos GDB a lanzar.</FILE></li>
</ul>

<p>En mi caso en particular la solución fue algo así:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls </span>core.<span class="k">*</span> | xargs <span class="nt">-I</span> <span class="o">{}</span> gdb <span class="nt">--batch</span> <span class="nt">-ex</span> bt <span class="o">{}</span>
</code></pre></div></div>

<p>Para los curiosos, la solución fue algo más compleja porque este comando
pertenecía a un script en python que obtenia el backtrace del core y con esa
salida se hacía un análisis para descartar aquellos cores que tenían un
backtrace con las misma funciones</p>

<h2 id="links">Links</h2>

<p><a>https://developers.redhat.com/blog/2021/04/30/the-gdb-developers-gnu-debugger-tutorial-part-1-getting-started-with-the-debugger#starting_gdb</a></p>

<p><a>https://developers.redhat.com/articles/2022/01/10/gdb-developers-gnu-debugger-tutorial-part-2-all-about-debuginfo#next_up_in_this_series</a></p>

<p><a>https://developers.redhat.com/articles/2021/12/09/printf-style-debugging-using-gdb-part-3#saving_the_insert_function_breakpoint</a></p>

<p><a>https://developers.redhat.com/blog/2015/04/28/remote-debugging-with-gdb</a></p>]]></content><author><name>Andres</name></author><category term="gdb" /><category term="desarrollo" /><category term="dev" /><category term="debug" /><summary type="html"><![CDATA[Hoy toca hablar sobre GDB el depurador estándar del compilador GNU. Normalmente los IDEs suelen integrar una interfaz gráfica para interactuar con los debuggers de cada lenguaje y no suele ser necesario aprender a usar un debugger por consola. Pero como siempre pasa, cuando necesitas ese conocimiento suele ser demasiado tarde y te arrepientes de tu dependencia a los entornos de desarrollo modernos. En cualquier caso aprender a usar GDB por consola te permite poder integrarlo en prácticamente en cualquier entorno de desarrollo.]]></summary></entry></feed>