From 178a33e000328e8f5558e5534859b4dc81a5d9e1 Mon Sep 17 00:00:00 2001 From: ThiagoMowszet Date: Wed, 3 Jan 2024 21:43:09 +0000 Subject: [PATCH] deploy: cbdb397e9438452417ab39fd7b9411b3f5406519 --- posts/2024/01/desarrollo-con-go-en-neovim/index.html | 2 +- search/index.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/posts/2024/01/desarrollo-con-go-en-neovim/index.html b/posts/2024/01/desarrollo-con-go-en-neovim/index.html index b0ad28d..bca81c3 100644 --- a/posts/2024/01/desarrollo-con-go-en-neovim/index.html +++ b/posts/2024/01/desarrollo-con-go-en-neovim/index.html @@ -38,7 +38,7 @@ ├── plugin/ │ └── packer_compiled.lua └── init.lua -

A continuación se explica para qué sirve cada carpeta.

Si bien entraremos en detalle más adelante de cada archivo y configuración, está bueno saber el set up de nuestro editor de texto.

Packer (Gestor de plugins)

Ya con nuestras carpetas generadas, vamos a instalar Packer que será nuestro gestor de plugins para Neovim.

Es cierto que este repositorio no se mantiene desde Agosto de 2023, y que muchos usuarios de Neovim están migrando a Lazy o Pckr (el sucesor de packer), pero para este post usaremos Packer, ya que sentara las bases de nuestro conocimiento para Neovim y luego podremos realizar otro post sobre la migración a Lazy (esto debido a que quien escribe, actualmente, no migro su gestor a otro 😅).

Para instalar packer, debemos de hacerlo de la siguiente manera:

Instalación en Unix, Linux.

git clone --depth 1 https://github.com/wbthomason/packer.nvim\
+

A continuación se explica para qué sirve cada carpeta.

Si bien entraremos en detalle más adelante de cada archivo y configuración, está bueno saber el set up de nuestro editor de texto.

Packer (Gestor de plugins)

Ya con nuestras carpetas generadas, vamos a instalar Packer que será nuestro gestor de plugins para Neovim.

Es cierto que este repositorio no se mantiene desde Agosto de 2023, y que muchos usuarios de Neovim están migrando a Lazy o Pckr (el sucesor de packer), pero para este post usaremos Packer, ya que sentará las bases de nuestro conocimiento para Neovim y luego podremos realizar otro post sobre la migración a Lazy (esto debido a que quien escribe, actualmente, no migró su gestor a otro 😅).

Para instalar packer, debemos de hacerlo de la siguiente manera:

Instalación en Unix, Linux.

git clone --depth 1 https://github.com/wbthomason/packer.nvim\
  ~/.local/share/nvim/site/pack/packer/start/packer.nvim
 

Instalación en Windows PowerShell.

git clone https://github.com/wbthomason/packer.nvim "$env:LOCALAPPDATA\nvim-data\site\pack\packer\start\packer.nvim"
 

Una vez instalado, iremos al siguiente path: .config/nvim/lua/tu-nombre/ e ingresaremos al archivo packer.lua en donde ingresaremos el siguiente código:

return require('packer').startup(function(use)
diff --git a/search/index.json b/search/index.json
index bbc1c33..f9db76c 100644
--- a/search/index.json
+++ b/search/index.json
@@ -1 +1 @@
-{"results":[{"href":"https://gophers-latam.github.io/posts/2024/01/desarrollo-con-go-en-neovim/","title":"Desarrollo con Go en Neovim","body":" Go con Neovim En este post vamos a ver cómo configurar desde cero Neovim y específicamente cómo personalizarlo para que nuestro desarrollo con Go sea altamente productivo.\nInstalación Lo primero que debemos de hacer es instalar Neovim.\nSi estamos en Windows, lo podemos hacer de la siguiente manera:\nwinget install Neovim.Neovim o también se puede realizar mediante gestores de paquetes externos como: Chocolatey o Scoop:\n# scoop scoop bucket add main scoop install neovim # chocolatey choco install neovim # (Podes usar `-y` para saltear automaticamente la confirmacion de mensajes). Y si estás en Linux, lo podés hacer de la siguiente manera, dependiendo de tu gestor de paquetes:\n# Arch sudo pacman -S neovim # Debian sudo apt-get install neovim # Fedora sudo dnf install -y neovim python3-neovim Para las demás distribuciones de Linux o para instalarlo de manera local, les dejo la documentación correspondiente.\nTener en cuenta que, dependiendo la distribución que se elija, será diferente la versión. Es decir, si descargamos Neovim en Ubuntu, vendrá con la versión 0.6 mientras que si se descarga en Manjaro, vendrán con la última versión estable (esto por la gestión de paquetes de cada distro).\nEs por esto que es siempre mejor descargar la última versión estable desde el código fuente, ya que nos aseguramos que nuestra versión sea la última y compatible con las últimas novedades de Neovim.\nGestión de carpetas Una vez instalado Neovim, vamos a generar nuestras carpetas.\nEn Linux, haremos lo siguiente en: ~/.config/nvim. Si nuestra carpeta no existe, la creamos.\nEn Windows, sera en: Local Disk (C:)/Users/tu-usuario/AppData/Local/nvim. Si nuestra carpeta no existe, la creamos.\nnvim/ ├── after/ │ └── plugin/ │ ├── tokyonight.lua │ └── telescope.lua ├── lua/ │ └── tu-nombre/ │ ├── init.lua │ ├── packer.lua │ ├── remap.lua │ └── set.lua ├── plugin/ │ └── packer_compiled.lua └── init.lua A continuación se explica para qué sirve cada carpeta.\nafter/plugin: Dentro de esta, creamos los .lua con el nombre del plugin que descarguemos para configurar como queramos nuestros plugins. En el arbol de referencia se ve los archivos tokyonight.lua y telescope.lua que nos sirven como ejemplo.\nlua/tu-nombre: Aquí, cambiaremos {tu-nombre} por tu nombre, en mi caso thiago, y dentro tendremos los archivos que nos servirán para descargar y setear nuestros atajos y configuraciones de Nvim.\nplugin: Esta carpeta debemos de generarla, pero su archivo (packer_compiled.lua) se genera automáticamente, en el ira toda nuestra configuración de Neovim. Es importante saber que no debemos de tocar este archivo.\ninit.lua: En este archivo, haremos el llamado de la carpeta \u0026ldquo;tu-nombre\u0026rdquo;, para que al iniciar se carguen automáticamente nuestras configuraciones.\nSi bien entraremos en detalle más adelante de cada archivo y configuración, está bueno saber el set up de nuestro editor de texto.\nPacker (Gestor de plugins) Ya con nuestras carpetas generadas, vamos a instalar Packer que será nuestro gestor de plugins para Neovim.\nEs cierto que este repositorio no se mantiene desde Agosto de 2023, y que muchos usuarios de Neovim están migrando a Lazy o Pckr (el sucesor de packer), pero para este post usaremos Packer, ya que sentara las bases de nuestro conocimiento para Neovim y luego podremos realizar otro post sobre la migración a Lazy (esto debido a que quien escribe, actualmente, no migro su gestor a otro 😅).\nPara instalar packer, debemos de hacerlo de la siguiente manera:\nInstalación en Unix, Linux.\ngit clone --depth 1 https://github.com/wbthomason/packer.nvim\\ ~/.local/share/nvim/site/pack/packer/start/packer.nvim Instalación en Windows PowerShell.\ngit clone https://github.com/wbthomason/packer.nvim \u0026#34;$env:LOCALAPPDATA\\nvim-data\\site\\pack\\packer\\start\\packer.nvim\u0026#34; Una vez instalado, iremos al siguiente path: .config/nvim/lua/tu-nombre/ e ingresaremos al archivo packer.lua en donde ingresaremos el siguiente código:\nreturn require(\u0026#39;packer\u0026#39;).startup(function(use) use \u0026#39;wbthomason/packer.nvim\u0026#39; end) Una vez hecho los cambios, haremos el siguiente comando en el modo normal: :so y enter. Y luego de esto haremos: :PackerInstall para instalar el nuevo paquete que agregamos.\nY ya que estamos realizando modificaciones, iremos a nvim/lua/tu-nombre/ y agregaremos los siguientes cambios en:\nnvim/lua/tu-nombre/init.lua require(\u0026#34;tu-nombre.set\u0026#34;) require(\u0026#34;tu-nombre.remap\u0026#34;) y en nuestro init.lua de nvim/init.lua: require(\u0026#34;tu-nombre\u0026#34;) Personalización ya con nuestra configuración básica, vamos a poner bonito nuestro editor de texto, ya que por default viene vacío.\nEn: lua/tu-nombre/set.lua, vamos a setear lo básico de nuestro editor de texto:\nvim.opt.nu = true -- Muestra el número de línea actual. vim.opt.smartindent = true -- Habilita el autoindentado inteligente. vim.opt.cursorline = true -- Resalta la línea en la que se encuentra el cursor. vim.opt.clipboard:append(\u0026#34;unnamedplus\u0026#34;) -- Configura el portapapeles para usar el registro \u0026#34;unnamedplus\u0026#34; (clipboard). vim.opt.termguicolors = true -- Habilita los colores de la terminal si es posible. vim.opt.tabstop = 4 vim.opt.softtabstop = 4 vim.opt.shiftwidth = 4 vim.opt.expandtab = true Y en lua/tu-nombre/remap.lua, vamos a realizar nuestros mapeos.\nPara ejecutar un plugin que instalamos se hace de la siguiente manera: :Plugin-a-Ejecutar\nPero esto es tedioso, por lo que en este archivo .lua, podemos configurarlo para que con ciertas combinaciones se ejecute el plugin que queramos.\nlocal keymap = vim.keymap -- Creamos esta variable para no estar constantemente escribiendo vim.keymap.set({}) local opts = { noremap = true, silent = true } -- Esto se hace para que nuestro atajo sea silencioso y no afecte tu vista. vim.g.mapleader = \u0026#34; \u0026#34; -- Seteamos la tecla espacio como lider. Esto nos servira mas adelante para mapear nuestros atajos. -- Usaremos este mapeo como ejemplo keymap.set(\u0026#34;n\u0026#34;, \u0026#34;\u0026lt;leader\u0026gt;q\u0026#34;, \u0026#34;:q\u0026lt;CR\u0026gt;\u0026#34;) -- Como bien sabemos, para salir de Nvim, se hace con :q. Entonces este mapeo, lo que nos permite es salir de nvim utilizando la combinacion de teclas: \u0026lt;leader\u0026gt; + q. -- \u0026lt;leader\u0026gt; lo seteamos mas arriba (vim.g.mapleader = \u0026#34; \u0026#34;), puede ser cualquier tecla y \u0026lt;CR\u0026gt; es un enter. -- Es lo mismo que hacer :q + enter, nada mas que lo asignamos a un mapeo y ejecutaremos esta funcion de forma facil y rapida. -- Ahora salir de Nvim no sera un problema. Para poder trabajar con temas de colores, lo haremos de la siguiente manera en: nvim/lua/tu-nombre/packer.lua\nreturn require(\u0026#39;packer\u0026#39;).startup(function(use) use \u0026#39;wbthomason/packer.nvim\u0026#39; -- Gestor de paquetes. use \u0026#39;folke/tokyonight.nvim\u0026#39; -- Esquema de colores. use(\u0026#34;nvim-treesitter/nvim-treesitter\u0026#34;, { run = \u0026#34;:TSUpdate\u0026#34; }) -- Nos provee un resaltado de colores en nuestro codigo. use({ \u0026#34;nvim-lualine/lualine.nvim\u0026#34;, -- Barra de estado. requires = { \u0026#34;kyazdani42/nvim-web-devicons\u0026#34;, opt = true }, }) use({ \u0026#34;nvim-tree/nvim-tree.lua\u0026#34;, -- Arbol de archivos. requires = { \u0026#34;nvim-tree/nvim-web-devicons\u0026#34;, }, }) use(\u0026#34;fatih/vim-go\u0026#34;) -- Para el desarrollo con Go. end) Una vez que tengamos los plugins que necesitemos, haremos lo que hicimos en pasos previos\n:so y enter y luego :PackerInstall para poder instarlos.\nUna vez instalados, debemos de ir a nvim/after/plugin/ y crear los archivos .lua para cada plugin que descargamos. Por ejemplo.\nnvim/after/plugin/lualine.nvim require(\u0026#39;lualine\u0026#39;).setup({ options = { theme = \u0026#34;auto\u0026#34; } }) nvim/after/plugin/nvim-treesitter.nvim require(\u0026#39;nvim-treesitter.configs\u0026#39;).setup({ ensure_installed = {\u0026#34;javascript\u0026#34;, \u0026#34;lua\u0026#34;, \u0026#34;json\u0026#34;, \u0026#34;html\u0026#34;, \u0026#34;css\u0026#34;, \u0026#34;typescript\u0026#34;, \u0026#34;markdown\u0026#34;, \u0026#34;go\u0026#34;, \u0026#34;python\u0026#34;}, sync_install = false, auto_install = true, highlight = {enable = true} }) Para que no se haga muy largo este post, haremos un video en el canal de YouTube de la comunidad para que sea más fácil y visual el uso de Nvim.\nEspero que este posts les sea de utilidad para aprender. Tambien les dejo mi configuración de Nvim en donde explico qué es, porque lo uso y todos los plugins que utilizo en mi día a día.\n"},{"href":"https://gophers-latam.github.io/posts/2023/12/manejo-de-memoria-101.-memoria-virtual-stack-y-heap/","title":"Manejo de memoria 101. Memoria virtual, Stack y Heap","body":" Puzzle. imagen de dominio público gentileza piqsels. https://www.piqsels.com/en/public-domain-photo-smyfi Que Go tiene un recolector de basura integrado lo hemos escuchado muchas veces. Significa que no tenemos que preocuparnos de liberar la memoria que nuestra aplicación usa, pero ¿Deberiamos entender el ciclo de uso de memoria de nuestras aplicaciones? ¿El recolector de basura nos da derecho a olvidar y usar y abusar de ese recurso?\nY, primero que nada ¿Que diablos es la memoria de la que tanto se habla?\nRenuncia de responsabilidades. No es trivial entender la forma en que los computadores trabajan. En aras de poder difundir intentaremos simplificar lo mas posible, en ocasiones, mas alla de lo recomendado. Muchos programadores hemos llegado a Go desde lenguajes de tipado débil, donde hemos tendido a mirar recursos como la memoria como si fueran gratuitos. Nada mas lejos de la verdad, como dice el viejo dicho No hay tal cosa como un almuerzo gratis y si queremos convertirnos en programadores mínimamente competentes debemos tener al menos una idea básica sobre la forma en que se manejan dichos recursos. He ahí la razón de este artículo.\nMemoria virtual Aquellos que ya tengan la escritura de algunos programas a su haber saben que cuando declaramos una variable, lo que estamos haciendo es asignar un identificador a una dirección de memoria en la que guardaremos datos (si nunca ha declarado una variable, hagase un favor y vaya al tour de go).\nMas o menos cuando hablamos de memoria todos pensamos en una grilla homogenea, con direcciones para acceder a cada casilla comodamente.\nPues bien, esa dirección de memoria no salió del aire por generación espontanea, existe físicamente de alguna forma en alguna parte.\nEn realidad, lo que llamamos memoria es una abstracción proporcionada por el sistema operativo, la cual oculta diferentes medios de almacenamiento.\nLos registros del procesador\nLa caché del procesador\nRAM\nArchivos en disco\nEtc.\nEn terminos generales, no sabemos en cual de estos medios de almacenamiento quedará almacenada nuestra variable. Solo sabemos que le hemos pedido memoria al sistema y que este nos la presentó adecuadamente para lograr nuestro objetivo. Claro, en aras de la eficiencia hay una gran probabilidad de que nuestro dato haya quedado guardado en RAM.\nEsta abstracción a la que hicimos referencia, es lo que llamamos memoria virtual, es administrada por el sistema operativo y es un recurso el cual debe ser solicitado.\nMemoria virtual es una abstracción que provee a cada proceso la ilusión de que tiene uso exclusivo sobre la memoria principal. Bryant, R. E. \u0026amp; O’Hallaron, D. R. (2016). Computer System: A Programmer’s Perspective (Third global edition). Pearson Education Limited.\nLa organización en forma de Celdas de memoria que nos es tan familiar es propia de la memoria virtual y como se imagina para que pueda funcionar se necesita una sofisticada interacción entre el sistema operativo y el hardware. Esta interacción se basa en un mapeo, direccionamiento o traslación entre las direcciones de la memoria virtual y el medio físico donde realmente se encuentre nuestro dato.\nCuando se ejecuta un programa, este tiene una visión uniforme de la memoria, la que llamamos Espacio de direcciones virtual, y dentro de este espacio hay dos áreas bien definidas que nos son de vital importancia.\nStack y Heap Stack El Stack es una región de la memoria que es localizada para cada hilo de ejecución de nuestros programas. En el contexto de Go, decimos que cada gorutina tiene su propio Stack. Su objetivo es contener variables locales, argumentos y valores de retorno de funciones, etc.\nCuando se invoca una función, se agrega una nueva capa en el Stack y cuando la función termina, esa capa se quita a su vez del Stack.\nLlamamos Localización/Allocation al proceso de reservar memoria para almacenar nuestros datos, y Deslocalización/Deallocation al proceso de liberarla una vez que ya no la necesitamos. El Stack tiene la ventaja de que permite acceder rápidamente a la memoria, ¡claro! porque los datos más recientes están siempre en la capa superior. Además, como cuando una función termina su ejecución, su capa asociada en el Stack se quita, ¡La memoria utilizada para los datos en esa capa se ve automáticamente deslocalizada!\nEl Stack empieza con espacio pre-localizado de un tamaño fijo, si el runtime detecta que se está quedando sin espacio, localiza más y como la memoría está localizada de antemano, guardar datos en el Stack es barato y automático.\nPara que una variable sea asignada en el Stack, deben cumplirse una serie de requisitos:\nTamaño fijo, conocido en tiempo de compilación\nEl runtime de Go debe ser capaz de determinar completamente su ciclo de vida\nSu tamaño no debe superar la capacidad máxima del Stack (mas las salvaguardas del runtime)\nEl Stack es rápido, localizar y dealocalizar en el es barato. Si estas y otras condiciones no son cumplidas, la variable escapará al Heap.\nHeap El Heap es el área del espacio de direcciones virtual que el runtime de Go solicita para almacenar los datos al ejecutar nuestro programa. El Heap crece dinámicamente y su objetivo es contener los datos que necesitamos persistan mas allá del tiempo de vida de una función o que son muy grandes para ser alojados en el stack.\nEl que nuestros datos escapen al Heap es costoso porque implica una localización, lo que significa que:\n1 Se verifica que el Heap tenga suficiente capacidad para el valor que almacenaremos en el.\n2 Si el punto 1 no se cumple, se debe solicitar más memoria al sistema operativo para el Heap. Se produce una System Call solicitando el recurso. En el mundo real este paso se realiza independientemente. El runtime monitorea constantemente el Heap y algunos algoritmos implementan un una meta, un límite de memoria, que una vez alcanzado o sobrepasado produce la solicitud de mas recursos al sistema operatvo.\n3 Se localiza la memoria en el Heap (por simplicidad incluyamos en este apartado la escritura de los datos que guardaremos).\n4 Se almacena en el Stack un puntero a la dirección de memoria inicial de la localización en el Heap.\nEl Heap es flexible, pero la flexibilidad viene con un costo ¡Todo esto es bastante trabajo para guardar un monton de datos! ¡Sea parsimonioso! Si, porque localizar en el Heap, si bien proporciona muchas ventajas, tiene un costo. Es por eso que en el ecosistema de Go usted encontrará librerías que se jactan de tener cero localizaciones, es decir, estan escritas tan cuidadosamente que no guardan datos en el Heap, sólo usan el Stack.\nEscapando al Heap Revisemos el siguiente código\nmain.go\npackage main func retString() string { retVal := \u0026#34;achu\u0026#34; return retVal } Hemos definido una función que devuelve un string. Construyamos un benchmark para que la podamos analizar.\nmain_test.go\npackage main import ( \u0026#34;testing\u0026#34; ) func Benchmark_retString(b *testing.B) { var a string b.ResetTimer() for i := 0; i \u0026lt;= b.N; i++ { a = retString() } b.StopTimer() b.Log(a) b.StartTimer() } Al ejecutar el benchmark veremos algo parecido al siguiente reporte\n$ go test -bench . -benchmem goos: linux goarch: amd64 pkg: exmem cpu: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz Benchmark_retString-16 1000000000 0.3356 ns/op 0 B/op 0 allocs/op Donde el benchmark nos informa con 0 allocs/op que han ocurrido 0 localizaciones al heap.\nReunamos más información. Agreguemos al comando el flag -gcflags \u0026quot;-m -m\u0026quot; que hará que el compilador realice un análisis de escape, el cual nos informará de movimientos de datos al heap.\n$ go test -gcflags \u0026#34;-m\u0026#34; -bench . -benchmem # exmem [exmem.test] ./main.go:3:6: can inline retString ./main_test.go:13:16: inlining call to retString ./main_test.go:7:26: leaking param: b ./main_test.go:17:7: ... argument does not escape ./main_test.go:17:8: a escapes to heap # exmem.test _testmain.go:37:6: can inline init.0 _testmain.go:45:24: inlining call to testing.MainStart _testmain.go:45:42: testdeps.TestDeps{} escapes to heap _testmain.go:45:24: \u0026amp;testing.M{...} escapes to heap goos: linux goarch: amd64 pkg: exmem cpu: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz Benchmark_retString-16 1000000000 0.3356 ns/op 0 B/op 0 allocs/op Continua reportandonos 0 localizaciones, pero ha agregado información interesante. Observe la siguiente línea en el reporte:\n./main_test.go:17:8: a escapes to heap Nos indica que la variable a escapa al Heap ¡Y nos dice el lugar exacto donde este escape ocurre!\nLa línea 17 de nuestro archivo de benchmark, precisamente donde pasamos la variable al logger.\nEsto demuestra que el escape no es producto de nuestro código pues el log de la variable está ahí solo como medio informativo y no es parte del mismo.\nConstruyamos otra función, esta vez una que devuelva un puntero a una variable local.\nfunc rePointerToString() *string { retVal := \u0026#34;achu\u0026#34; return \u0026amp;retVal } Y agreguemos el benchmark correspondiente.\nfunc Benchmark_retPointerToString(b *testing.B) { var a *string b.ResetTimer() for i := 0; i \u0026lt;= b.N; i++ { a = rePointerToString() } b.StopTimer() b.Log(a) b.StartTimer() } Al ejecutar el benchmark veremos un reporte parecido a lo que sigue:\ngoos: linux goarch: amd64 pkg: exmem cpu: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz Benchmark_retPointerToString Benchmark_retPointerToString-16 50917658\t24.86 ns/op\t16 B/op\t1 allocs/op PASS ok exmem\t1.292s ¡Una localización que reserva 16 bytes! Agreguemos un nivel más al análisis con -gcflags \u0026quot;-m\u0026quot;\n./main.go:3:6: can inline retString ./main.go:8:6: can inline rePointerToString ./main_test.go:13:16: inlining call to retString ./main_test.go:27:24: inlining call to rePointerToString ./main.go:9:2: moved to heap: retVal ./main_test.go:7:26: leaking param: b ./main_test.go:17:7: ... argument does not escape ./main_test.go:17:8: a escapes to heap ./main_test.go:21:35: leaking param: b ./main_test.go:27:24: moved to heap: retVal ./main_test.go:31:7: ... argument does not escape # exmem.test _testmain.go:39:6: can inline init.0 _testmain.go:47:24: inlining call to testing.MainStart _testmain.go:47:42: testdeps.TestDeps{} escapes to heap _testmain.go:47:24: \u0026amp;testing.M{...} escapes to heap goos: linux goarch: amd64 pkg: exmem cpu: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz Benchmark_retPointerToString Benchmark_retPointerToString-16 49800909 25.77 ns/op 16 B/op 1 allocs/op Otra vez podemos ver varias cosas interesantes:\n./main.go:9:2: moved to heap: retVal ... ./main_test.go:17:8: a escapes to heap ... ./main_test.go:27:24: moved to heap: retVal ... En el archivo main.go, donde definimos la función rePointerToString el análisis de escape nos informa que en la línea 9, donde definimos a la variable retVal como un string, el compilador ha movido la variable al Heap ¡Cuando aún no hemos devuelto su puntero! ¡Lo hacemos recien en la línea 10! ¡Claro! el compilador ha detectado que devolveremos un puntero al valor string almacenado en la variable local, por lo que ha determinado almacenar a la variable en el Heap directamente ¡Aun antes de que se produzca el retorno del puntero!\nHablar sobre memoria y otros temas relacionados con arquitectura de computadores es apasionante, pero es para nunca terminar.\nRecapitulando, hemos dado un recorrido introductorio a vuelo de pajaro sobre la memoria revisando al Stack y al Heap, con algunos ejemplos en código. Conocimos al flag -gcflags \u0026quot;-m\u0026quot; para agregar análisis de escape a nuestros tests y benchmarks.\nSi le gustó este artículo no olvide compartirlo.\n"},{"href":"https://gophers-latam.github.io/posts/2023/12/fuga-de-gorutinas/","title":"Fuga de gorutinas","body":" Fugas. imagen de dominio público gentileza pxfuel. https://www.pxfuel.com/en/free-photo-ojgpw Sabemos que las gorutinas son una de las mas importantes primitivas que Go pone a nuestra disposición para el manejo de concurrencia. Por eso se hace necesaria una forma de prevenir fugas de gorutinas.\nSi aun no empieza a estudiar concurrencia en Go ¡Le sugerimos ver este video de la comunidad antes de leer este artículo! Una fuga o leak de gorutinas es cuando nuestra aplicación crea gorutinas sin tener el cuidado de terminarlas correctamente.\nObservemos el siguiente ejemplo. Seguramente reconocerá el problema, en este caso estamos enviando información por un canal y no tenemos a nadie que consuma dicho canal.\npackage main import ( \u0026#34;fmt\u0026#34; \u0026#34;math/rand\u0026#34; \u0026#34;runtime\u0026#34; \u0026#34;time\u0026#34; ) func send() int { n := rand.Intn(1000) time.Sleep(200 * time.Millisecond) return n } func submit() int { ch := make(chan int) go func() { ch \u0026lt;- send() }() go func() { ch \u0026lt;- send() }() go func() { ch \u0026lt;- send() }() go func() { ch \u0026lt;- send() }() return \u0026lt;-ch } func submitAll() { for i := 0; i \u0026lt; 5; i++ { submit() } } func main() { submitAll() fmt.Printf(\u0026#34;número de gorutinas: %d\\n\u0026#34;, runtime.NumGoroutine()) } Si ejecutamos este programa veremos lo siguiente:\n$ go run main.go número de gorutinas: 16 Imprime número de gorutinas: 16 ¿Por que razón? Porque el contenido del loop se itera 4 veces y en cada iteración engendra 4 gorutinas en la función submit. Ingenuamente podriamos estar esperando que al salir del ámbito de la función submit las gorutinas se hubiesen cerrado ¡Pero no es así! ¡Siguen corriendo al final de su proceso como lo demuestra la impresión!\nUna fuga o leak de gorutinas es cuando nuestra aplicación crea gorutinas sin tener el cuidado de terminarlas correctamente. Ahora bien, si nuestra aplicación terminara en este punto, no habría problema alguno, pues al acabar su ejecución ya es responsabilidad del sistema operativo realizar las labores de limpieza. Pero muchas veces usamos Go para construir aplicaciones que se ejecutan continuamente sin parar y que se espera que no se detengan, como servicios, apis, etc. En este tipo de aplicaciones, un escenario como el presentado en el ejemplo es insostenible.\nGo reserva una cantidad de memoria específica inicial para que las gorutinas usen como su stack, si bien esta cantidad puede variar de versión en versión, la cantidad actual se puede revisar en el repositorio de GO\nEste stack puede ir creciendo según el proceso que se ejecute dentro de la gorutina.\nEl problema Entonces, ¿Que pasará si nuestra aplicación sufre de fuga de gorutinas y engendra 100000 de ellas durante un periódo de un año sin terminarlas correctamente?\nPues asumiendo optimistamente que el proceso que se ejecuta dentro de nuestras gorutinas fugadas devuelven correctamente la memoria, y que el stack asignado a cada una de ellas sigue teniendo un tamaño de 2kB, tendriamos para ese momento cerca de 200MB de memoria usada por la aplicación que no podrán ser recuperados por el recolector de basura ¡Porque las gorutinas todavía están ejecutandose! ¡Porque nunca nos aseguramos de terminarlas correctamente!\nSi no cuidamos de terminar correctamente las gorutinas que nuestra aplicación engendra, corremos el riesgo de enfrentar Out Of Memory Errors Si ejecutamos nuestra aplicación en algún tipo de contenedor o máquina virtual con un límite duro de memoría, esto puede llegar a ocasionar out of memory errors\n¿Que podemos hacer?\nPreviniendo fugas de gorutinas Inevitablemente debemos aprender y convertirnos en expertos en el modelo de memoria de Go y en su modelo de concurrencia. Esto es de vital importancia, pues de la misma forma que un carpintero es responsable de usar de forma segura su sierra circular, taladro y otros implementos, nosotros como programadores somos responsables de usar correctamente las herramientas de nuestro oficio.\nEn esto cae la construcción de tests y benchmarks y el uso profilactico de herramientas de perfilado como pprof asegurandonos de que las pruebas se realicen por un periodo de tiempo conveniente, pues no es lo mismo perfilar un servicio el mismo día en que lo lanzamos a correr, que dos meses después.\nOtra herramienta muy útil es goleak del equipo de Uber Go, que presenta una forma muy simple de testear que nuestras gorutinas se cierren correctamente.\nSe usa de la siguiente forma:\n1 Debemos importarla a nuestro proyecto $ go get -u go.uber.org/goleak\n2 Debemos construir un test que incluya el flujo completo de nuestras gorutinas. Usaremos el mismo ejemplo anterior\nImportamos la utilidad y nos aseguramos de invocarla usando defer para que se garantice su ejecución al final de nuestro proceso.\npackage main import ( \u0026#34;testing\u0026#34; \u0026#34;go.uber.org/goleak\u0026#34; ) func TestGorutineLeak(t *testing.T) { defer goleak.VerifyNone(t) for i := 0; i \u0026lt; 4; i++ { submitAll() } } ¡Y listo! Al ejecutar el test, si goleak detecta fugas de gorutinas, el test fallará\n$ go test ./... === RUN TestGorutineLeak /home/jacobopus/projects/go/goru/main_test.go:15: found unexpected goroutines: [Goroutine 7 in state chan send, with goru.submit.func1 on top of the stack: goru.submit.func1() /home/jacobopus/projects/go/goru/main.go:19 +0x30 created by goru.submit in goroutine 6 /home/jacobopus/projects/go/goru/main.go:19 +0x66 ] --- FAIL: TestGorutineLeak (4.46s) FAIL Puede revisar la documentación de goleak para descubrir otras formas de uso.\nNo olvide compartir este articulo si fue de su agrado.\n"},{"href":"https://gophers-latam.github.io/posts/2023/10/el-tour-de-go-ahora-en-espa%C3%B1ol/","title":"El tour de Go ahora en Español","body":" Tour de Go en Español ¡Logramos algo increíble como comunidad! La traducción del tour de Go al español. Estamos emocionados de compartir con todos ustedes el increíble logro que hemos alcanzado juntos: la completa traducción del tour de Go al español.\nEste proyecto fue un esfuerzo colaborativo en el que nuestra comunidad contribuyó con su tiempo y conocimiento para hacer que esta herramienta esté disponible para toda la comunidad hispanohablante. ¡El resultado es asombroso!\n¿Qué es El Tour de Go? 👩‍💻👨‍💻 Para aquellos que aún no lo conocen, el \u0026ldquo;Tour de Go\u0026rdquo; es una excelente introducción al lenguaje de programación Go. Proporciona ejemplos interactivos y explicaciones detalladas, lo que lo convierte en una herramienta invaluable para aprender Go.\nEl poder de la colaboración 👥 La clave de este logro fue la colaboración. Cada uno de nosotros aportó con sus habilidades y conocimientos para llevar a cabo esta traducción. Desde los que realizaron las primeras traducciones hasta aquellos que revisaron y pulieron cada detalle, cada uno de ustedes fue fundamental.\n¿Qué significa esto para la comunidad? 💡 La traducción del tour al español no solo significa que más personas tendrán acceso a esta valiosa herramienta, sino que también fortalece nuestra comunidad y nos posiciona como un grupo que puede lograr grandes cosas cuando trabajamos juntos.\n¿Qué sigue? 🛠️ Nuestro trabajo no termina aquí. Continuaremos buscando maneras de contribuir y crecer como comunidad. Si tienes ideas o proyectos en mente, ¡no dudes en compartirlas!\nUna vez más, felicitaciones a todos los que participaron en este proyecto. ¡Han demostrado el increíble poder de la comunidad de Gophers Latam!\n¡Sigamos construyendo juntos! 🚀 Tour de Go Link del repositorio: https://github.com/gophers-latam/go-tour-es\nLink profesional sobre la comunidad: https://es.linkedin.com/posts/thiago-mowszet_github-gophers-latamgo-tour-es-traducci%C3%B3n-activity-7118450478593536000-JlrR\n"},{"href":"https://gophers-latam.github.io/posts/2023/03/handlers-con-timeout/","title":"Handlers Con Timeout","body":" go handlers En algunas oportunidades, vamos a necesitar un comportamiento muy determinístico en nuestras APIs, ya sea porque el negocio así lo requiere o los clientes. Tal vez, un comportamiento que se mantenga alejado de cualquier sorpresa, puede ser el máximo de duración que le queremos dejar como ventana para que un respuesta sea entregada, en caso de excederlo, ahora si como el título lo dice, devolvemos un timeout\u0026hellip; pero, qué es un timeout?\nEn principio sabemos que contamos con 2 estados para representarlo, pero no se parecen mucho ya que están en centenas distintas, unos es 408 request timeout y el otro es 504 Gateway timeout. Si leemos un poco las especificaciones, ninguno de los dos nos calza justo para lo que queremos, el 408 nos dice que el cliente \u0026ldquo;se tardó demasiado para enviar su request\u0026rdquo;, desde la RFC dice lo siguiente:\nThe client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time.\nY para su contraparte del lado del servidor:\nThe server was acting as a gateway or proxy and did not receive a timely response from the upstream server.\nEntonces, para la responder la pregunta, concluimos que un timeout es que esperamos demasiado por algo, y no sucedió, ademas, lo consideramos un error.\nCómo hacemos nuestras funciones de Timeout? En los lenguajes de programación modernos, encontramos built-in algunas formas de manejar estos casos de uso. En Golang, por ejemplo el paquete context tiene constructores para crear uno que expire y se cancele después de cierto tiempo.\nDentro del paquete net/http también nos encontramos con muchos timeouts como por ejemplo en la struct http.Client para hacer requests y http.Server es otra que tampoco se queda afuera de tener este tipo de configuración.\nPor ahora, tenemos: context, http.Client y Server, servidores TCP y UDP, etc. Podemos resumir que siempre que haya una conexión hacia fuera (ya sea cliente o servidor) vamos a poder configurar un timeout.\nCómo nos sirven en los web handlers? Antes, debemos aclarar que es un middleware, en cualquier lenguaje, ya que es un concepto y no una implementación específica de Golang.\nEntonces, decimos que son funciones con la misma firma que un handler (o controlador web), que recibe los mismos parámetros para operar como una petición HTTP. Al ser iguales, nos permite ejecutarlo previamente de una forma sencilla y pre-ejecutar operaciones que nos ayuden a nuestro negocio. Un claro ejemplo son validaciones de token JWT, agregar request ID unicos, sumarle datos al contexto (esto si es mas estilo gopher). En nuestro caso, vamos a tener un middleware que se encargue de reemplazar el contexto, por otro que tenga un timeout, para que no tarde mas de tanto tiempo y si no, falla. Nos va a ayudar a garantizar un tiempo de respuesta de máxima, por las buenas o por las malas.\nLo llevamos a código Como middleware, podemos usar uno que ya existe y está dentro del paquete http, es http.Timeout y dentro de su firma, vamos a pasarle un http.Handler, el tiempo de espera que vamos a soportar y por último (este no me gusta mucho) un mensaje como string, donde nos quita un poco de flexibilidad, a mi entender, []byte nos daría un espectro mas amplio a la hora de retornar los valores.\nPodemos implementarlo como un wrapper general a todo el multiplexer y que todos ejecuten el middleware, este tiene como ventaja que escribimos una sola vez, pero perdemos granularidad. func main() { mux := http.NewServeMux() mux.HandleFunc(\u0026#34;/\u0026#34;, func(w http.ResponseWriter, r *http.Request) { //.... }) muxWithMiddleware := http.TimeoutHandler(mux, time.Second*5, \u0026#34;timeout!\u0026#34;) log.Fatal(http.ListenAndServe(\u0026#34;:8080\u0026#34;, muxWithMiddleware)) } Por último, tenemos otro camino, para tener un control espercífico en cada handler que expongamos. func main() { mux := http.NewServeMux() helloHandler := http.TimeoutHandler(wrapHandlerFunc(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(\u0026#34;hello with timeout!\u0026#34;)) })), time.Second*5, \u0026#34;timeout\u0026#34;) mux.Handle(\u0026#34;/\u0026#34;, helloHandler) } func wrapHandlerFunc(handler http.Handler) http.Handler { wrapped := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set(\u0026#34;Content-Type\u0026#34;, \u0026#34;application/json\u0026#34;) handler.ServeHTTP(w, r) }) return wrapped } Conclusiones Vemos la flexibilidad que tenemos para exponer funciones en un servior web que tenemos en Golang. Siempre nos da muchas facilidades y opciones, a su vez, puede ser un poco confuso porque no sabemos bien cual usar. Como pequeño consejo, no nos fritemos la cabeza pensando y comparando, tan solo elijamos una con un análisis superficial y despues nos queda el aprendizaje.\nPara cerrar el tema técnico, estamos re-utilizando una funcion de la stdlib de Go, por lo que no es necesario que nostros pensemos esa lógica, también, muchos de los Frameworks web como Echo, Gin y Fiber (seguramente entre varios otros) ya traen sus middleware de timeout y es de una implementacion muy similar a la que acabamos de ver.\nEspero que les haya gustado la explicación! nos vemos dentro de poco y cualquier tema que quieran que tratemos lo pueden dejar en comentarios.\n"},{"href":"https://gophers-latam.github.io/posts/2022/08/intro-go-mistakes-okno/","title":"Intro Go Mistakes Okno","body":" okno Se comparte el concepto o contexto de algunos errores basicos con su definición acompañado de ejemplo y solución.\nIndice: Código y organización del proyecto Código y organización del proyecto - Sombreado de variable (shadowing) no deseado La parte de una aplicación donde un enlace de nombre es válido. En Go, un nombre de variable declarado en un bloque se puede volver a declarar en un bloque interno. Este principio, llamado sombreado de variable, es propenso a errores.\nEjemplo:\nvar client *http.Client if tracing { client, err := createClientWithTracing() if err != nil { return err } log.Println(client) } else { client, err := createDefaultClient() if err != nil { return err } log.Println(client) } 1 Declarar una variable client 2 Crear un cliente HTTP con tracing habilitado, la variable client está sombreada en este bloque 3 Crear un cliente HTTP predeterminado, la variable client también se sombrea en este bloque Como resultado, de este ejemplo, la variable externa siempre será nula.\nSolución:\nLa primera opción es usar variables temporales en los bloques internos:\nvar client *http.Client if tracing { c, err := createClientWithTracing() if err != nil { return err } client = c } else { // Same logic } 1 Crear una variable temporal c 2 Asignar esta variable temporal a client Otra opción es usar el operador de asignación (=) en los bloques internos para asignar directamente los resultados de la función a la variable. Sin embargo, requiere crear una variable de error ya que el operador de asignación solo funciona si ya se ha declarado un nombre de variable:\nvar client *http.Client var err error if tracing { client, err = createClientWithTracing() if err != nil { return err } } else { // Same logic } 1 Declarar una variable de error 2 Usar operador de asignación para asignar el *http.Client devuelto a la variable client directamente - Código anidado innecesario Un aspecto crítico de la legibilidad es el número de niveles anidados. Un código se califica como legible en función de múltiples criterios, como el nombrado, la consistencia, el formato, etc. Un código legible requerirá menos esfuerzo cognitivo para mantener un modelo mental; por lo tanto, será más fácil de leer y mantener.\nEjemplo:\nTiempo o dificultad para entender la siguiente función a detalle.\nfunc join(s1, s2 string, max int) (string, error) { if s1 == \u0026#34;\u0026#34; { return \u0026#34;\u0026#34;, errors.New(\u0026#34;s1 is empty\u0026#34;) } else { if s2 == \u0026#34;\u0026#34; { return \u0026#34;\u0026#34;, errors.New(\u0026#34;s2 is empty\u0026#34;) } else { concat, err := concatenate(s1, s2) if err != nil { return \u0026#34;\u0026#34;, err } else { if len(concat) \u0026gt; max { return concat[:max], nil } else { return concat, nil } } } } } func concatenate(s1 string, s2 string) (string, error) { // ... } Solución:\nHacer la tarea de aplicar legibilidad y consistencia sobre la misma función, implementandola de manera diferente:\nfunc join(s1, s2 string, max int) (string, error) { if s1 == \u0026#34;\u0026#34; { return \u0026#34;\u0026#34;, errors.New(\u0026#34;s1 is empty\u0026#34;) } if s2 == \u0026#34;\u0026#34; { return \u0026#34;\u0026#34;, errors.New(\u0026#34;s2 is empty\u0026#34;) } concat, err := concatenate(s1, s2) if err != nil { return \u0026#34;\u0026#34;, err } if len(concat) \u0026gt; max { return concat[:max], nil } return concat, nil } func concatenate(s1 string, s2 string) (string, error) { // ... } El resultado para requerir menos carga cognitiva. - Mal uso de las funciones init En principio init es una función que no toma argumentos y no devuelve ningún resultado (una función func()). Cuando se inicializa un paquete, se evalúan todas las declaraciones de constantes y variables del paquete. El principal problema reside cuando se ha creado un flujo de uso que se vuelve dificil de entender o seguir y por falta de entendimiento se provocan errores no manejados que se volveran dificiles de mitigar o controlar.\nEjemplo:\nOlvidar o no haber entendido el sentido o punto de entrada para ejecuion de init.\npackage main import \u0026#34;fmt\u0026#34; var a = func() int { fmt.Println(\u0026#34;var\u0026#34;) return 0 }() func init() { fmt.Println(\u0026#34;init\u0026#34;) } func main() { fmt.Println(\u0026#34;main\u0026#34;) } Salida\n1: var 2: init 3: main Ejemplo de flujo usando Redis en base de codigo personal.\nSolución:\nHay criterios en sentido idiomatico como:\nEvitar incluir funciones init en codigo que sera probado con paquete de testing.\nNo hacer que sean de ambito global a menos que sea realmente requerido.\nEvitar usar para conexiones a base de datos.\nInvestigar situaciones en las que pueden ser útiles, como definir una configuración estática. De lo contrario, y en la mayoría de los casos, manejar las inicializaciones a través de funciones personalizadas.\nEbook recomendado: 100 Go Mistakes Que trata a fondo algunos errores sobre: Tipos de datos, Estructuras de control, Strings en detalle, Funciones y métodos, Manejo de errores, Concurrencia: Fundamentos y Práctica, Librería estándar, Pruebas y Optimizaciones\n"},{"href":"https://gophers-latam.github.io/posts/2021/12/ecosistema-lenguage-go/","title":"Ecosistema lenguage Go","body":" json to go Go, también conocido como Golang, es un lenguaje de programación de tipado estático desarrollado por Robert Griesemer, Rob Pike y Ken Thompson en Google.\nGo es sintácticamente similar a C, pero viene con seguridad de memoria, recolección de basura, tipificación estructural y sincronización al estilo CSP.\nHay dos implementaciones principales:\nEl paquete de alojamiento de Google que se dirige a múltiples sistemas operativos, dispositivos móviles y WebAssembly.\ngccgo (un front) y GCC\nGo es expresivo, conciso, limpio y eficiente. Los mecanismos simultáneos facilitan la escritura de aplicaciones que aprovechan al máximo las máquinas en red de varios núcleos, mientras que el sistema más nuevo permite crear aplicaciones modulares y flexibles. Compila código máquina con bastante rapidez, pero tiene la conveniencia de la recolección de basura y el poder de reflejar el tiempo de ejecución. - Un lenguaje rápido, bien tipado y bien proporcionado que actúa como un lenguaje interpretado dinámico.\nNada hace que un programador se emocione más que descubrir un nuevo lenguaje de programación. Al examinar el estado actual del software y hardware informático, podemos ver por qué tenemos que cambiar a un nuevo lenguaje como Go. Durante la última década, la potencia de procesamiento en bruto ha aumentado ligeramente y el rendimiento de la frecuencia de la CPU se ha mantenido casi constante durante una década.\nGo, se libero cuando los procesadores de varios núcleos ya estaban disponibles. Es por eso que Go se hizo pensando en la coordinación. Sus mecanismos síncronos facilitan la escritura de aplicaciones que utilizan más sistemas multinúcleo y en red. Si bien el nuevo tipo de sistema Go hace posible construir aplicaciones modulares flexibles, en lugar de centrarse en teorías, en métodos del mundo real para construir aplicaciones de próxima generación en la nube, así como computación avanzada y computación distribuidas.\nHistórico Go es un lenguaje de programación procedimental que se lanzó en 2009 como lenguaje de programación de código abierto. Actualmente se utiliza en varios sistemas operativos de Google. El Go Compiler es compatible con Linux, Mac OS, Windows y una variedad de sistemas operativos BSD como FreeBSD. En términos de arquitectura de procesador, la arquitectura X86, la arquitectura X64, la arquitectura ARM y la arquitectura Power específica de IBM también son compatibles con Go.\nArquitectura Lingüística Go tiene muchas herramientas poderosas de análisis estático. Uno de ellos es go fmt, que diseña su código basándose en el estilo Go propuesto. Esto puede eliminar muchos comentarios en un proyecto normal y alentar a su equipo a concentrarse en el código. Lenguaje de programación desarrollado y compilado de forma nativa, que pertenece principalmente a la familia de lenguajes C en términos de sintaxis básica.\nComo C y C++, está compilado en código de máquina, por lo que no necesitamos entornos como CLR y JVM para ejecutar programas Go. Esto ayuda especialmente al compilar programas grandes. Lenguaje simple y minimalista con diseño original de Go para en lugar del clásico Thread a goroutines. En Go, el límite de tamaño de pila mínimo se elimina de 4 KB a 8 KB cuando se crea una goroutine.\nDiseño Go está influenciado por C, pero con un mayor énfasis en la simplicidad y la seguridad. Esto incluye:\nPatrones de adopción de sintaxis y entorno que son más comunes en lenguajes dinámicos: Declaración de variable corta opcional e introducción inicial por inferencia de tipo.\nEdición rápida.\nAdministración de paquetes remotos (go download) y documentación de paquetes en línea.\nEnfoques distintivos para problemas específicos.\nSincronización inicial: procesos de estilo (Gurvin), canales y expresiones selectivas.\nUn sistema de interfaz en lugar de herencia virtual e incrustación de tipo en lugar de la herencia no virtual.\nUn kit de herramientas que, de forma predeterminada, crea binarios de interfaz nativa sin dependencias externas.\nLa tendencia a preservar las propiedades del lenguaje es lo suficientemente simple como para mantener en calam la cabeza de un programador, en parte eliminando características que son comunes a lenguajes similares.\nGo es Back o Front? El código Go se puede ejecutar usando goper.js en el navegador. Pero el hecho es que la mayoría de los desarrolladores recurren a los lenguajes de programación Front y JavaScript para desarrollar su lado del cliente. Go es más preferido como lenguaje de respaldo y ofrece un alto rendimiento para el desarrollo simultáneo de aplicaciones de servidor.\nAlgunas aplicaciones populares desarrolladas en Go Algunos de los proyectos de código abierto en Go son:\nCaddy: servidor web HTTP 2 de código abierto con capacidad HTTPS automática\nCockroachDB: una base de datos SQL de código abierto, escalable y compatible\nDocker: incluye un conjunto de herramientas de implementación de Linux.\nEthereum: implementación de Go-Ethereum, máquina de bloqueo de máquina virtual, Ethereum virtual para criptomoneda Ether\nHugo: un generador de sitios estáticos\nInfluxDB: base de datos de código abierto para series de datos de alto acceso con requisitos de alto rendimiento\nInterPlanetary File System: un contenido y un protocolo de direccionamiento de medios punto a punto.\nJuju: una herramienta de evaluación de servicios de Canonical, paquetes de Ubuntu Linux.\nKubernetes: sistema de gestión de contenedores\nLightning Network: una red de bitcoins para transacciones rápidas de bitcoins.\nMattermost: un sistema de chat en equipo.\nOpenShift: una plataforma de computación en la nube proporcionada por Red Hat como servicio.\nSnappy: un administrador de paquetes para Ubuntu Touch desarrollado por Canonical.\nSyncthing: software de sincronización de archivos cliente/servidor de código abierto.\nTerraform: una herramienta de código abierto para la infraestructura multimedia en la nube proporcionada por HashiCorp.\nEmpresas y sitios notables que han utilizado GO (generalmente junto con otros lenguajes, no exclusivamente) Cacoo: para renderizar paneles de usuario y microservicios usando Go y gRPC.\nChango: una empresa de publicidad que utiliza sistemas de precios en tiempo real.\nCloud Foundry: una plataforma como servicio.\nCloudFlare: se utiliza para el proxy de codificación Delta Railgun, su servicio de DNS distribuido, así como herramientas para encriptación, registro, procesamiento de flujo y acceso a sitios SPDY.\nCoreOS: un sistema operativo basado en Linux que utiliza el repositorio Docker y el repositorio rkt.\nDropbox: que ha migrado algunos de sus componentes vitales de Python a Go.\nEthereum: una moneda digital\nGoogle: se utiliza para muchos proyectos, incluido el servidor de descargas (dl.google.com).\nHyperledger Fabric: un proyecto de código abierto único.\nMongoDB: una herramienta para administrar instancias de MongoDB\nNetflix: se utiliza para dos partes de la arquitectura de su servidor.\nNovartis: para sistema de inventario interno\nNutanix: se utiliza para una variedad de microservicios en su empresa Cloud OS.\nPlug.dj: un sitio web interactivo relacionado con la transmisión de música social en línea.\nSendGrid: un boulder, servicio de entrega de correo electrónico y servicio de gestión de transacciones.\nSoundCloud: se utiliza para \u0026ldquo;docenas de sistemas\u0026rdquo;.\nEmpalme: se utiliza para todo el backend (API y analizadores) en su plataforma de colaboración musical en línea.\nThoughtWorks: Algunas herramientas y aplicaciones para entrega continua y mensajería instantánea (CoyIM).\nTwitch.tv: para el sistema de chat basado en IRC (migración desde Python).\nUber: para manejar grandes volúmenes de consultas basadas en geovallas\nGo Features Go compila código como lenguajes de bajo nivel como C++/C. Esto significa que funciona casi tan bien como lenguajes de bajo nivel. También utiliza la recolección de basura para recolectar y eliminar objetos.\nEl gráfico siguente muestra que Go es casi tan eficiente como C++/C, mientras mantiene la sintaxis simple como Ruby, Python y otros lenguajes. Esta es una situación en la que todos ganan para los humanos y los procesadores! El alto rendimiento como C++/C y Java proporciona una sincronización altamente eficiente para codificar en términos divertidos como Python y Perl. El software optimizado puede ejecutarse en hardware más barato y lento, como los dispositivos IoT, y generalmente tiene un mayor impacto en la experiencia del usuario final. El modelo de memoria Go agrega una nueva regla para enviar y recibir canales de búfer para indicar explícitamente que un canal de búfer puede usarse como un simple spammer.\nDescripción general de las características principales del lenguaje:\nCompilación: Go genera compilaciones binarias para sus aplicaciones con todas las dependencias. No se requiere instalación de traductor o runtime.\nRecolección de basura: Para recolectar desperdicios de baja latencia, opta por una administración automática de memoria que sea eficiente y sincrónica. La gestión de la memoria es intencionadamente más fácil que C y C++. Los objetos dedicados recolectan basura de forma dinámica.\nSeguro: Go es un lenguaje de tipado estático que admite la seguridad de tipos. El compilador detecta los errores antes de la ejecución.\nSintaxis similar a C: La sintaxis Go recuerda a la familia C, pero con solo 25 palabras clave simples, es fácil de analizar sin tablas/símbolos de información de tipo y un diseño de notificación similar a Pascal.\nVarios paradigmas: Go admite varios patrones de programación, incluida la programación esencial, orientada a objetos (OOP) y la programación funcional.\nLibrería estándar: Go tiene una potente librería estándar de paquetes para respaldar el desarrollo de aplicaciones Go.\nDocumentación sencilla: GoDoc es una herramienta de análisis de código estático que genera documentos estándar simplificados directamente desde el código.\nSoporte de pruebas naturalmente: Soporte de prueba integrado en la librería estándar. Sin necesidad de dependencia adicional Si tiene un archivo llamado thing.go, escriba sus pruebas en otro archivo llamado thing_test.go y ejecute \u0026ldquo;go test\u0026rdquo;.\nGo Tools La distribución principal de Go incluye herramientas para crear, probar y analizar código:\ngo build: crea un binario usando solo sus archivos fuente.\ngo test: se utiliza para pruebas unitarias y microbenchmarks.\ngo fmt: se utiliza para formatear el código.\ngo get: se utiliza para recuperar e instalar paquetes remotos.\ngo vet: un analizador estático que busca posibles vulnerabilidades o errores en el código.\ngo run: un atajo para construir y ejecutar código directamente.\ngo doc: para mostrar documentos o enviarlos a través de HTTP\ngo rename: se utiliza para renombrar variables, funciones, etc. en tipo seguro.\ngo generate: un método estándar para llamar a un generador de código\nTambién incluye soporte de depuración y perfiles, herramientas de medición de tiempo de ejecución. El ecosistema de herramientas de terceros se ha agregado a la distribución estándar, incluido gocode, que permite completar automáticamente el código en muchos editores de texto. goimports (por un miembro del equipo de Go) que automáticamente elimina o agrega paquetes según sea necesario, y errcheck, que detecta errores de código y puede ignorarlos. Hay complementos para agregar soporte de idioma en algunos editores de texto. Hay varios IDE disponibles, incluidos LiteIDE y el \u0026ldquo;Go IDE multiplataforma\u0026rdquo; y GoLand.\nAplicaciones del lenguaje Go está diseñado específicamente como lenguaje de programación para grandes sistemas distribuidos y servidores de red altamente escalables. En este sentido, reemplaza a C++ y Java en la pila de software de Google. Muchos equipos buscan crear nuevos servidores en Go. Algunos incluso están migrando bases de código existentes. Algunas de las tecnologías de Google que utiliza a diario tienen componentes escritos en Go.\nDado que este es un lenguaje de programación relativamente nuevo, muchos preguntan para qué es adecuado.\nUn vistazo a algunos de sus beneficios:\nIdeal para el desarrollo web\nExcelente para scripts de línea de comandos\nSe puede utilizar para aplicaciones de servidor de red.\nSe puede utilizar para el desarrollo de front-end.\nLos desarrolladores disfrutan usando Go porque tiene un entorno de desarrollo completo, y aprender Go es muy fácil, incluso para desarrolladores sin experiencia. Una de las razones de esto se debe al gran ecosistema de herramientas, por lo que es muy útil para proyectos grandes y conjuntos. Esto lo convierte en una excelente opción para programar software propietario. Si se está buscando más beneficios, Go fue creado y es mantenido por Google, que tiene una de las infraestructuras de nube más importantes del mundo y puede ser a gran escala.\nData Science Es una ciencia multidisciplinaria que utiliza métodos, procesos, algoritmos y sistemas científicos para extraer conocimientos e ideas de datos estructurados y no estructurados. La ciencia de datos es el concepto de combinar estadísticas, análisis de datos, aprendizaje automático y métodos relacionados para comprender y analizar fenómenos reales con datos. Extrae técnicas y teorías que han surgido de muchos campos de las matemáticas, la estadística, la informática y la ciencia de la información. El ganador del premio Turing, Jim Gray, ve la ciencia de datos como el \u0026ldquo;cuarto modelo\u0026rdquo; de la ciencia (experimental, teórico, computacional y ahora basado en datos) y afirma que \u0026ldquo;todo lo relacionado con la ciencia está cambiando debido al impacto de la tecnología de la información\u0026rdquo;.\nEn la actualidad, a menudo se usa indistintamente con conceptos anteriores, como análisis empresarial, inteligencia empresarial, modelado de previsión y estadísticas. Si bien muchos programas académicos ahora tienen un título en ciencia de datos, no existe un consenso sobre la definición del contenido curricular apropiado. Sin embargo, muchos proyectos de ciencia de datos y Big Data no han podido lograr resultados útiles, a menudo debido a la falta de gestión y utilización de recursos.\n« Go demuestra cada vez pruebas más rápidas, codificación fácil en lenguajes de programación concurrentes altamente eficientes. Por lo general, es la próxima generación de ciencia de datos, aprendizaje automático e inteligencia artificial, porque existe un gran equilibrio entre la productividad y la retención de código. Muchos prototipos de científicos de datos, que luego son transferidos a producción por otra persona, deja que Go haga ambas cosas. »\n"},{"href":"https://gophers-latam.github.io/posts/2021/08/go-talks/","title":"Go Talks","body":" talks Este post contiene charlas de Go que se pueden leer siguiendo los vinculos de cada título listado.\n2019 playground-v3.slide: Playground v3 2017 state-of-go-may.slide\nexporting-go\nstate-of-go-aug\n2016 refactor.article: Codebase Refactoring (with help from Go)\napplicative.slide: Program your next server in Go\nasm.slide: The Design of the Go Assembler\nstate-of-go.slide: The State of Go\ntoken.slide: Stacks of Tokens\nprototype-your-design\n2015 dynamic-tools.slide: Go Dynamic Tools\ngo-for-java-programmers.slide: Go for Java Programmers\ngo4cpp.slide: Go for C++ developers\ngofmt-cn.slide: gofmt 的文化演变\ngofmt-en.slide: The Cultural Evolution of gofmt\ngogo.slide: Go in Go\ngophercon-go-on-mobile.slide: Go on Mobile\ngophercon-goevolution.slide: The Evolution of Go\ngotham-grpc.slide: gRPC Go\nhow-go-was-made.slide: How Go was made\njson.slide: JSON, interfaces, and go generate\nkeeping-up.slide: Keeping up with the Gophers\nsimplicity-is-complicated.slide: Simplicity is Complicated\nstate-of-go.slide: The State of Go\ntricks.slide: Stupid Gopher Tricks\n2014 c2go.slide: Go, from C to Go\ncamlistore.slide: - Camlistore: Android, ARM, App Engine, anywhere.\ncompiling.slide: - Go: Easy to Read, Hard to Compile\ndroidcon.slide: Go on Android\ngo1.3.slide: Toward Go 1.3\ngo4gophers.slide: Go for gophers\ngo4java.slide: Go for Javaneros (Javaïstes?)\ngocon-tokyo.slide: - Go: 90% Perfect, 100% of the time.\ngotham-context.slide: Cancelation, Context, and Plumbing\ngothamgo-android.slide: Go on Android\nhammers.slide: Gophers With Hammers\nhellogophers.slide: Hello, Gophers!\nnames.slide: What\u0026rsquo;s in a name?\norganizeio.slide: Organizing Go code\nplayground.slide: Inside the Go playground\nreadability.slide: When in Go, do as Gophers do\nresearch.slide: The Research Problems of Implementing Go\nresearch2.slide: More Research Problems of Implementing Go\nstate-of-go.slide: The State of Go\nstate-of-the-gopher.slide: The State of the Gopher (Oct)\nstatic-analysis.slide: Static analysis tools\ntaste.slide: A Taste of Go\ntesting.slide: Testing Techniques\n2013 advconc.slide: Advanced Go Concurrency Patterns\nbestpractices.slide: Twelve Go Best Practices\ndistsys.slide: Go, for Distributed Systems\ngo-sreops.slide: Go Language for Ops and Site Reliability Engineering\ngo1.1.slide: What\u0026rsquo;s new in Go 1.1\ngo4python.slide: Go for Pythonistas\nhighperf.slide: High Performance Apps with Go on App Engine\noscon-dl.slide: dl.google.com: Powered by Go\n2012 10things.slide: 10 things you (probably) don\u0026rsquo;t know about Go\nchat.slide: - Go: code that grows with grace\nconcurrency.slide: Go Concurrency Patterns\ngo-docs.slide: Go docs\ngo1.slide: The Path to Go 1\ngoforc.slide: Go for C programmers\ninsidepresent.slide: Inside the \u0026ldquo;present\u0026rdquo; tool\nsimple.slide: - Go: a simple programming environment\nsplash.slide: Go at Google\ntutorial.slide: Get started with Go\nwaza.slide: Concurrency is not Parallelism\nzen.slide: Go and the Zen of Python\n2011 lex.slide: Lexical Scanning in Go 2010 ExpressivenessOfGo-2010\ngo_talk-20100112\ngo_talk-20100121\ngo_talk-20100323\ngofrontend-gcc-summit-2010\n2009 go_talk-20091030 "},{"href":"https://gophers-latam.github.io/posts/2021/06/conversi%C3%B3n-json-a-go/","title":"Conversión JSON a Go","body":" json to go Uno de los formatos de datos que se encuentra con mucha frecuencia en programación, principalmente web, es JavaScript Object Notation (JSON).\nCuando se recibe datos en formato JSON de representación, debe convertirse a un formato que sea fácil de manipular en el programa en Go. Hay algunas herramientas en línea que permiten convertir fuente JSON directamente en estructuras Go, aunque haciendo una simple búsqueda google.com/search?q=json+to+go se ve varidad de resultados, las destacadas o pioneras son:\nJSON-to-Go - mholt.github.io/json-to-go/\nTransform - transform.tools/json-to-go\nJson2Struct - json2struct.mervine.net/\nPor último como extensión de navegador para mejor accesibilidad existe json to go para Chrome.\n"},{"href":"https://gophers-latam.github.io/posts/2021/05/golang-implementaci%C3%B3n-del-almacenamiento-en-cach%C3%A9/","title":"Golang: Implementación del almacenamiento en caché","body":" go cache El almacenamiento en caché de datos en una aplicación web a veces es necesario para evitar solicitar datos estáticos de una base de datos o un servicio externo una y otra vez. Go no proporciona ningún paquete integrado en la librería estándar para almacenar en caché las respuestas, pero lo admite a través de paquetes externos creados por la comunidad.\nHay una serie de paquetes, como github.com/coocood/freecache, github.com/patrickmn/go-cache, github.com/eko/gocache y github.com/etcd-io/etcd (gRPC) que pueden ayudar a implementar el almacenamiento en caché. Por parte de la comunidad de Gophers LATAM se busca crear algo relacionado: github.com/gophers-latam/GoKey\nPara este post se estará usando github.com/patrickmn/go-cache para implementar un ejemplo de uso.\nEjemplo: Primero crear un directorio para el código fuente de prueba e inicializar un go module. [go mod init cache-example]\nLuego crear archivo .go, donde se hará un caché por medio de la librería y se completará con datos sobre el arranque del servidor, de la siguiente manera:\npackage main import ( \u0026#34;fmt\u0026#34; \u0026#34;log\u0026#34; \u0026#34;net/http\u0026#34; \u0026#34;time\u0026#34; \u0026#34;github.com/patrickmn/go-cache\u0026#34; ) const ( CONN_PORT = \u0026#34;8080\u0026#34; ) var newCache *cache.Cache func init() { newCache = cache.New(5*time.Minute, 10*time.Minute) newCache.Set(\u0026#34;gophers\u0026#34;, \u0026#34;gophers latam\u0026#34;, cache.DefaultExpiration) } func getFromCache(w http.ResponseWriter, r *http.Request) { gophers, found := newCache.Get(\u0026#34;gophers\u0026#34;) if found { log.Print(\u0026#34;Key encontrada en caché con valor, como : \u0026#34;, gophers.(string)) fmt.Fprintf(w, \u0026#34;Hola \u0026#34;+gophers.(string)) } else { log.Print(\u0026#34;Key no encontrada en caché : \u0026#34;, \u0026#34;gophers\u0026#34;) fmt.Fprintf(w, \u0026#34;Key no encontrada en caché\u0026#34;) } } func main() { http.HandleFunc(\u0026#34;/\u0026#34;, getFromCache) err := http.ListenAndServe(\u0026#34;:\u0026#34;+CONN_PORT, nil) if err != nil { log.Fatal(\u0026#34;error al iniciar el servidor http : \u0026#34;, err) return } } Ejecutar el código. Como funciona: Una vez iniciado, el servidor HTTP comenzará a escuchar localmente en el puerto 8080. Al inicio, la clave con el nombre gophers con un valor como gophers latam se agregará a la caché.\nAl navegar por http://localhost:8080/ se leerá un valor de key de la caché y lo agregará a Hola como se muestra en la siguiente captura de pantalla:\nLog en terminal:\nSe ha especificado el tiempo de caducidad de los datos de la caché en el programa como 5 minutos, lo que significa que la clave que se ha creado en la caché al iniciar el servidor no estará allí después de 5 minutos. Por lo tanto, acceder a la misma URL nuevamente después de 5 minutos devolverá que la clave no es encontrada en la caché del servidor, de la siguiente manera:\nUsando var newCache *cache.Cache, se declara una caché privada.\nSe actualiza la función init() donde se crea un caché con 5 minutos de tiempo de vencimiento y 10 minutos de intervalo de limpieza, y se agrega un elemento a caché con una clave como gophers con su valor como gophers latam y su valor de vencimiento como 0, lo que significa que se quiere usar el tiempo de vencimiento predeterminado de la caché.\nPara usarse se define el controlador getFromCache donde se recupera el valor de una clave en caché. Si se encuentra, se escribe en respuesta HTTP, de lo contrario, se escribe el mensaje Key no encontrada en caché.\n"},{"href":"https://gophers-latam.github.io/posts/2021/05/golang-init-func/","title":"Golang: Init func","body":" init func Cada programa en Go debe tener un paquete main con una función main para ser ejecutado. Sin embargo, esto impone algunas limitaciones para determinadas soluciones, como las librerías. Imagina que importamos una librería a nuestro código.\nUna librería no está diseñada para ser ejecutada, ofrece estructuras de datos, métodos, funciones, etc. Es probable que las librerías ni siquiera tengan un paquete main. Si esta librería requiere alguna configuración inicial antes de ser invocada (inicializar variables, detectar el sistema operativo, etc.) parece imposible.\nGo define las funciones init que se ejecutan una vez por paquete. Cuando importamos un paquete, el tiempo de ejecución (runtime) de Go sigue este orden:\nInicializar los paquetes importados de forma recursiva. Inicializar y asignar valores a las variables. Ejecutar las funciones de init. Ejemplos: 1. - En el resultado para el código de ejemplo se muestra cómo la inicialización sigue el orden descrito anteriormente. La función xSetter se invoca primero, seguida de init y la función main.\npackage main import \u0026#34;fmt\u0026#34; var x = xSetter() func xSetter() int { fmt.Println(\u0026#34;xSetter\u0026#34;) return 42 } func init() { fmt.Println(\u0026#34;Init function\u0026#34;) } func main() { fmt.Println(\u0026#34;Este es el main\u0026#34;) } Salida en ejecución: La función init no tiene argumentos ni devuelve ningún valor. Un paquete puede tener varias funciones init y no se pueden invocar desde ninguna parte del código.\nGo no permite importar un paquete si no se usa dentro del código. Sin embargo, es posible que solo nos interese ejecutar las funciones init de un paquete. Esto es lo que Go llama los efectos secundarios de un paquete (side effects pkg). Por lo general, esto se hace en paquetes que realizan alguna operación de arranque o registro. La instrucción especial import _ solo llama a las funciones init de un paquete que no requiere su uso dentro del código.\n2. - Ejemplo usando import _ : importado el paquete \u0026ldquo;a\u0026rdquo; para utilizar sus efectos secundarios. Observar que este paquete tiene dos funciones init que se ejecutan antes del init del paquete de importación. [go mod init ejemplo2]\nejemplo2/main.go\npackage main import ( \u0026#34;fmt\u0026#34; _ \u0026#34;ejemplo2/a\u0026#34; ) func init() { fmt.Println(\u0026#34;Init desde mi programa\u0026#34;) } func main() { fmt.Println(\u0026#34;Mi programa\u0026#34;) } ejemplo2/a/a.go\npackage a import \u0026#34;fmt\u0026#34; func init() { fmt.Println(\u0026#34;Init 1 desde paquete a\u0026#34;) } func init() { fmt.Println(\u0026#34;Init 2 desde paquete a\u0026#34;) } Salida en ejecución: "},{"href":"https://gophers-latam.github.io/posts/2021/04/golang-referencia-esencial-go-modules/","title":"Golang: Referencia esencial Go modules","body":" Go Modules Esta es una hoja de trucos esenciales, no una referencia oficial. Con el fin de que sea conciso, se omitieron aspectos menos frecuentes, dado que este sitio desde su repositorio esta abierto a cambios de contribuidores en la comunidad de Gophers LATAM cualquiera puede hacer cambios que mejoren este contenido.\nInicio rápido Gestión de dependencias go get -d github.com/path/to/module # agregar o actualizar dep (-v log verboso) go get -d github.com/dep/two/v2@v2.1.0 # usar una versión específica go get -d github.com/dep/commit@branch # usar una rama específica go get -d -u ./... # actualizar módulos utilizados en subdirectorios go get -d github.com/dep/legacy@none # eliminar dep Comandos útiles go mod tidy # organizar y limpiar go.mod and go.sum go mod download # descargar deps en caché de módulos go mod init github.com/path/to/module # inicializar nuevo módulo go mod why -m github.com/path/to/module # por qué el módulo es una dependencia? go install github.com/path/to/bin@latest # construir e instalar binario Anatomía del go.mod // ruta de importación de Go con lugar donde se aloja el módulo module github.com/my/library go 1.16 // versión utilizada para desarrollar módulo (usar nuevas funciones de lenguaje) require ( github.com/dep/one v1.0.0 // v2 y posteriores tienen versión principal en ruta del módulo github.com/dep/two/v2 v2.3.0 // \u0026#34;pseudo-versión\u0026#34; que se refiere a un commit y no a una versión etiquetada. github.com/dep/other v0.0.0-20180523231146-b3f5c0f6e5f1 github.com/dep/legacy v2.0.0+incompatible // \u0026#34;incompatible\u0026#34; significa que el paquete aún no se ha migrado a nuevos módulos de Go ) exclude github.com/dep/legacy v1.9.2 // evitar que se use una versión de módulo específica replace github.com/dep/one =\u0026gt; github.com/fork/one // reemplazar este módulo con este otro Selección de versión mínima (MVS) Para crear un programa, Go necesita saber exactamente qué dependencias necesita y qué versión usar.\nGo utiliza MVS como una forma sencilla y predecible de decidir qué versión utilizar.\nFunciona así:\nEl módulo desde el que está ejecutando es el \u0026ldquo;módulo main\u0026rdquo;\nEncuentra todas las dependencias que necesita el módulo principal (de forma recursiva, usando los archivos go.mod de las dependencias)\nPara cada dependencia, usar la mayor versión que cualquier go.mod haya especificado explícitamente\nEjemplo: En este ejemplo, el módulo principal depende de A 1.0 y B 2.1.\nDado que B 2.1 depende de A 1.1, esta es la versión de A que se utilizará.\nDado que se usa A 1.1, también en C 1.1.\nLa lista final de dependencias es:\nA 1.1 B 2.1 C 1.1 Fuentes: Referencia oficial: https://golang.org/ref/mod\nVersión del post original: https://encore.dev/guide/go.mod\n"},{"href":"https://gophers-latam.github.io/posts/2021/04/golang-la-interfaz-vac%C3%ADa/","title":"Golang: La interfaz vacía","body":" Interface type Explicación breve sobre el tipo interfaz vacia y nula.\nSe define una interfaz vacía como interface{}, y puede contener un valor de cualquier tipo:\nvar i interface{} i = \u0026#34;hola gophers\u0026#34; fmt.Println(i) Si se necesita probar si una interfaz es de cierto tipo, se usa una aserción de tipo:\nvar i interface{} i = \u0026#34;hola gophers\u0026#34; s, ok := i.(string) if !ok { fmt.Println(\u0026#34;s is not type string\u0026#34;) } fmt.Println(s) En el ejemplo anterior, i es un tipo string, por lo que el segundo valor de retorno de la aserción de tipo es verdadero (ok) y s contiene el valor por debajo de este. Si hubiera sido de otro tipo, como un int, entonces el ok habría sido falso y s habría sido el valor cero del tipo que se estaba tratando de afirmar, es decir, 0.\nInterfaz nula Una interfaz en Go es esencialmente una tupla que contiene el tipo y el valor subyacentes. Para que una interfaz se considere nula, tanto el tipo como el valor deben ser nulos (nil). Ejemplo:\npackage main import ( \u0026#34;fmt\u0026#34; ) func main() { var i interface{} fmt.Println(i == nil) fmt.Printf(\u0026#34;%T, %v\\n\u0026#34;, i, i) var s *string fmt.Println(\u0026#34;s == nil:\u0026#34;, s == nil) i = s fmt.Println(\u0026#34;i == nil:\u0026#34;, i == nil) fmt.Printf(\u0026#34;%T, %v\\n\u0026#34;, i, i) Salida:\ntrue \u0026lt;nil\u0026gt;, \u0026lt;nil\u0026gt; s == nil: true i == nil: false *string, \u0026lt;nil\u0026gt; Observar que la variable s es nil, pero cuando se establece la interfaz i en s, se verifica si i es nil, i no se considera nil. Esto se debe a que la interfaz tiene un tipo concreto por debajo establecido y las interfaces solo son nulas cuando tanto el tipo concreto como el valor son nulos.\n"},{"href":"https://gophers-latam.github.io/search/","title":"Búsqueda","body":""},{"href":"https://gophers-latam.github.io/posts/2021/04/golang-mantener-actualizado-el-sdk/","title":"Golang: Mantener actualizado el SDK","body":" Update Go Como ocurre con todos los lenguajes de programación, hay actualizaciones periódicas de las herramientas de desarrollo de Go. El SDK Go son binarios nativos que no dependen de un tiempo de ejecución independiente, por lo que no hay que preocuparse de que la actualización del entorno de desarrollo pueda hacer que los programas actualmente implementados fallen. Puede tenerse programas compilados con diferentes versiones de Go ejecutándose simultáneamente en la misma computadora o máquina virtual.\nDesde Go 1.2, ha habido una nueva versión importante aproximadamente cada seis meses. También hay versiones menores con correcciones de errores y seguridad que se publican según sea necesario. Dados los rápidos ciclos de desarrollo y el compromiso del equipo de Go con la compatibilidad con versiones anteriores, las versiones de Go tienden a ser incrementales en lugar de expansivas. La promesa de compatibilidad de Go es una descripción detallada de cómo el equipo de Go planea evitar romper el código de Go. Dice que no habrá cambios retrógrados en el lenguaje o la librería estándar para cualquier versión de Go que comience con 1, a menos que el cambio sea necesario para un error o corrección de seguridad. Sin embargo, puede haber (y ha habido) cambios incompatibles con versiones anteriores en los indicadores o la funcionalidad de los comandos go.\nA pesar de estas garantías de compatibilidad con versiones anteriores, los errores ocurren, por lo que es natural querer asegurarse de que una nueva versión no rompa los programas personales ya hechos. Una opción es instalar un entorno Go secundario. Por ejemplo, si actualmente se está ejecutando la versión 1.15.2 y se quiere probar la versión 1.16.3, debe usarse los siguientes comandos:\ngo get golang.org/dl/go.1.16.3 go1.16.3 download Luego se puede usar el comando go1.16.3 en lugar del comando go para ver si la versión 1.16.3 funciona para los programas ya hechos anteriormente con la nueva versión de Go:\ngo1.16.3 build Una vez que se haya validado que el código funciona, puede eliminarse el entorno secundario buscando el GOROOT, eliminándolo y luego eliminando el binario del directorio $GOPATH/bin. A continuación, las indicaciones de cómo hacerlo en Mac OS, Linux y BSD respectivamente:\ngo1.16.3 env GOROOT /Users/gobook/sdk/go1.16.3 rm -rf $(go1.16.3 env GOROOT) rm $(go env GOPATH)/bin/go1.16.3 Cuando se está listo para actualizar las herramientas de desarrollo de Go instaladas en la computadora, los usuarios de Mac y Windows tienen la ruta más fácil. Aquellos que instalaron con brew o chocolatey pueden usar esas herramientas para actualizar. Aquellos que usaron los instaladores en golang.org/dl pueden descargar el último instalador, que elimina la versión anterior cuando se instala la nueva.\nLos usuarios de Linux y BSD en general deben descargar la última versión, mover la versión anterior a un directorio de respaldo, expandir la nueva versión y luego eliminar la versión anterior, algo así:\nmv /usr/local/go /usr/local/old-go tar -C /usr/local -xzf go1.16.3.linux-amd64.tar.gz rm -rf /usr/local/old-go Como nota final, igual en cada versión que sale en el canal del Discord #📰fuente-noticias se comparte automáticamente del canal de Twitter oficial como obtener la nueva versión.\n"},{"href":"https://gophers-latam.github.io/posts/2021/04/golang-resumen-reglas/","title":"Golang: Resumen reglas","body":" Go Police El lenguaje de programación Go fue creado para hacer el trabajo fácilmente.\nGo tiene conceptos similares a los lenguajes imperativos y el tipado estático.\nTambién es rápido en la compilación, rápido de ejecutar e implementar. Grande y complejo.\nEn este post, se explican conceptos básicos de Go tratando algunos conceptos o reglas importantes.\nLos principales temas tratados son los siguientes:\nEscribir comentarios. Librerías e importación. Funciones. Tipos de datos. Valores de retorno con nombre. Variables y memoria. Control de sentencias. Generar funciones. Ejecución diferida. Interfaces. Múltiples entradas. Manejo de errores. Ejecución simultánea. Escribir comentarios: Para escribir un comentario de una línea\n// comentario de una sola línea Escribir un comentario con más de una línea\n/* comentario de multi-línea */ Librerías e importación: Cada archivo de código fuente comienza con la palabra clave package. La palabra clave main se utiliza para identificar el archivo como un archivo operativo, no como una librería.\npackage main Para importar un paquete de la librería estándar, terceros o personal al archivo, usamos la instrucción import de la siguiente manera:\nimport ( \u0026#34;fmt\u0026#34; // paquete en la librería estándar \u0026#34;io/ioutil\u0026#34; // se aplican funciones de E/S m \u0026#34;math\u0026#34; // usando la letra m para acortar o hacer alias del nombre de la librería de funciones matemáticas \u0026#34;net/http\u0026#34; // web server \u0026#34;os\u0026#34; // funciones a nivel del sistema operativo, como el manejo de archivos \u0026#34;strconv\u0026#34; // conversiones de texto ) Funciones: Las funciones se definen mediante la palabra func seguida del nombre de la función.\nLa función main es privada y es la entrada al archivo ejecutable del programa (Go usa llaves ornamentadas {} para definir partes / bloques).\nfunc main() { // salida de texto en la unidad main en stdout (salida estandar) con Println de fmt (stdlib pkg) fmt.Println (\u0026#34;Hello world!\u0026#34;) // llamar a una función del paquete actual beyondHello() } Las funciones necesitan paréntesis que reciben parámetros, e incluso en ausencia de parámetros, se requieren paréntesis.\nfunc beyondHello() { // declaración de variable (la variable debe declararse antes de usarse) var x int // dar valor a la variable x = 3 // definición corta usando := incluye definición de variable, especificando su tipo y dándole valor y := 4 // una función que devuelve dos valores separados sum, prod := learnMultiple (x, y) // imprimir salida de forma sencilla y directa fmt.Println (\u0026#34;sum:\u0026#34;, sum, \u0026#34;prod:\u0026#34;, prod) learnTypes() } La definición de función puede tener múltiples coeficientes y valores de retorno. Por ejemplo, learnMultiple toma los coeficientes x, y \u0026hellip; y devuelve dos valores de sum y prod de tipo Int.\nfunc learnMultiple (x, y int) (sum, prod int) { // separar los valores devueltos con una coma regular return x + y, x * y } Tipos de datos: func learnTypes() { // las declaraciones cortas generalmente cumplen el propósito deseado // definir una variable de texto usando comillas dobles str := \u0026#34;Learn Go!\u0026#34; // definir una variable de texto con comillas simples s2 := `A \u0026#34;raw\u0026#34; string literal can include line breaks.` // definir variable tipo runa que es otro nombre para el tipo int32 que contiene unicode g := \u0026#39;Σ\u0026#39; // float f := 3.14195 // definición de número complejo (Complex) c := 3 + 4i // definir variables usando var var u uint = 7 // número natural (entero positivo) var pi float32 = 22. / 7 // un decimal de 32 bits // definición corta byte (es otro nombre para uint8) n := byte (\u0026#39;\\n\u0026#39;) // arrays tienen un tamaño fijo, y son fijos en momento de compilación // definir un array int de 4 elementos con un valor inicial de cero var a4 [4] int // definir un array de 3 elementos con valores 3, 1 y 5 a3 := [...] int {3, 1, 5} Go ofrece un tipo de datos llamado Slices. Los Slices entendibles como \u0026ldquo;rebanadas\u0026rdquo;, \u0026ldquo;porciones\u0026rdquo;, \u0026ldquo;segmentos\u0026rdquo; tienen un tamaño dinámico. Las matrices (array) y los segmentos (slice) tienen ventajas, pero los casos de uso de los segmentos son más comunes. La siguiente instrucción define un segmento de tipo int\n// observar la diferencia entre el array y la declaración del slice, donde cuando // el slice está definido no hay un número que determine su tamaño s3: = [] int {4, 5, 9} // definir un tipo int con cuatro elementos con valores cero s4: = make ([] int, 4) // solo definir, y no hay selección var d2 [] [] float64 // método para convertir el tipo de texto en slice bs: = [] byte (\u0026#34;a slice\u0026#34;) Por la naturaleza de los slice dinámicos, es posible agregar nuevos elementos usando la función append incorporada. Primero se pasa el slice al que queremos agregar y luego los elementos que queremos agregar.\ns := [] int {1, 2, 3} s = append (s, 4, 5, 6) // se imprimirá un slice con el siguiente contenido [1 2 3 4 5 6] fmt.Println (s) Para agregar un slice a otro slice, pasamos los dos slices en la función en lugar de pasar elementos individuales, y siguiendo el segundo slice con tres puntos.\ns = append (s, [] int {7, 8, 9} ...) // se imprimirá un slice con el siguiente contenido [1 2 3 4 5 6 7 8 9] fmt.Println (s) La siguiente instrucción define las variables p y q como punteros en dos variables de tipo int que contienen dos valores devueltos por la función learnMemory:\np, q := learnMemory() // tema de reglas por ver Cuando un asterisco precede a un cursor, significa el valor de la variable a la que se refiere el cursor, como en el siguiente ejemplo los valores de las dos variables devueltas por la función learnMemory:\nfmt.Println (*p, *q) Los mapas (maps) en Go son arrays dinámicos y modificables que son similares al tipo de diccionario o hash en otros lenguajes.\n// aquí un mapa cuya clave es tipo texto y los valores de los elementos numéricos. m: = map [string] int {\u0026#34;three\u0026#34;: 3, \u0026#34;four\u0026#34;: 4} m [\u0026#34;one\u0026#34;] = 1 Las variables no utilizadas son errores. El subrayado, guion bajo, operador blanco o Blank Identifier de la siguiente manera hace usar la variable pero ignora valores al mismo tiempo:\n_, _, _, _, _, _, _, _, _, _ = str, s2, g, f, u, pi, n, a3, s4, bs Valores de retorno con nombre: A diferencia de otros lenguajes, las funciones pueden tener valores de retorno con nombre. Donde el nombre se devuelve al valor de la función en la línea de la definición de la función, esta característica permite regresar fácilmente desde cualquier punto de la función además del uso de la palabra return solo sin mencionar nada después:\nfunc learnNamedReturns (x, y int) (z int) { z = x * y // aquí implícitamente significa devolver el valor de la variable z return } Nota: El lenguaje Go se basa en gran medida en la recolección de basura. Go tiene indicadores pero no cálculos (puede confundir un cursor vacío, pero no puede aumentar el cursor). Tener cuidado con valores de retorno de nil pointer reference.\nVariables y memoria: Las variables p y q a continuación son indicadores del tipo int y representan valores de retorno en la función. Cuando se define, los cursores están vacíos; sin embargo, el uso de la función incorporada new hace que el valor de la variable numérica p se refiera a cero, y por lo tanto ocupa espacio en la memoria; es decir, p ya no está vacío.\nfunc learnMemory() (p, q* int) { p = new(int) // definir un slice de 20 elementos como una sola unidad en la memoria. s := make([] int, 20) // dar valor a un elemento s[3] = 7 // definir una nueva variable local a nivel de función r := -2 // devolver dos valores de la función, que son direcciones de memoria // para las variables s y r, respectivamente. return \u0026amp;s[3], \u0026amp;r } func expensiveComputation() float64 { return m.Exp (10) } Control de sentencias Las sentencias condicionales requieren corchetes ornamentados y no requieren paréntesis.\nfunc learnFlowControl() { if true {fmt.Println (\u0026#34;told ya\u0026#34; ) } if false { // Rusters. } else { // Gophers. } Usar la instrucción switch si se necesita escribir más de una secuencia condicional.\nx := 42.0 switch x { case 0: case 1: case 42: case 43: default: } Como sentencia condicional, la cláusula for no toma paréntesis. Las variables definidas en la cláusula for son visibles a nivel de la sentencia.\nfor x: = 0; x \u0026lt;3; x ++ { fmt.Println (\u0026#34;iteration\u0026#34;, x) } La instrucción for es la única instrucción de iteración en el lenguaje Go y tiene otra formas, de la siguiente manera:\n// repetición infinita for { // break para detener la repetición break // continue para ir a la siguiente iteración continue } Se puede utilizar el range para pasar elementos de array, slice, text string, map, channel.\nEl range de canal (channel) devuelve un valor, y dos valores cuando se usa en slice, array, text string, o map.\n// ejemplo: for key, value := range map [string] int {\u0026#34;one\u0026#34;: 1, \u0026#34;two\u0026#34;: 2, \u0026#34;three\u0026#34;: 3} { // imprimir el valor de cada elemento del mapa fmt.Printf (\u0026#34;key =% s, value =% d \\n\u0026#34;, key, value) } Usar el guión bajo (_) contra valor de retorno en la clave si solo se desea el valor, de la siguiente manera:\nfor _, name: = range [] string {\u0026#34;Bob\u0026#34;, \u0026#34;Bill\u0026#34;, \u0026#34;Joe\u0026#34;} { fmt.Printf (\u0026#34;Hello,% s \\n\u0026#34;, name) } Se puede usar la declaración corta con la sentencia condicional para que se defina una variable y luego se verifique en la sentencia de condición.\nPor ejemplo se define una variable y, se le da un valor y luego se coloca la condición de la sentencia para que estén separadas por un punto y coma.\nif y := expensiveComputation(); y \u0026gt; x { x = y } Se puede definir funciones anónimas falsas directamente en el código.\nxBig := func() bool { // x:= 42 que fue declarada antes donde de menciona la sentencia switch return x \u0026gt; 10000 } x = 99999 // la función xBig ahora devuelve el valor verdadero fmt.Println (\u0026#34;xBig:\u0026#34;, xBig()) x = 1.3e3 // Después de modificar el valor de x a 1.3e3 que es igual a 1300 (es decir, mayor que 1000) // la función xBig devuelve falso fmt.Println (\u0026#34;xBig:\u0026#34;, xBig()) Además de lo anterior, es posible definir función fantasma y llamarla en la misma línea y pasarla a otra función siempre que se llame directamente y el tipo de resultado sea consistente con lo esperado en el parámetro de la función.\nfmt.Println (\u0026#34;Add + double two numbers:\u0026#34;, func (a, b int) int { return (a + b) * 2 } (10, 2)) goto love love: learnFunctionFactory() // Una función que devuelve una función learnDefer() // Dormir learnInterfaces() // Trabajar con interfaces } Generar funciones Se puede tratar las funciones como objetos separados. Por ejemplo, crear una función y el valor de retorno es otra.\nfunc learnFunctionFactory() { Los dos métodos siguientes para imprimir la oración son iguales, pero el segundo método es más claro, más legible y común.\nfmt.Println(sentenceFactory (\u0026#34;summer\u0026#34;) (\u0026#34;A beautiful\u0026#34;, \u0026#34;day!\u0026#34;)) d: = sentenceFactory (\u0026#34;summer\u0026#34;) fmt.Println(d (\u0026#34;A beautiful\u0026#34;, \u0026#34;day!\u0026#34;)) fmt.Println(d (\u0026#34;A lazy\u0026#34;, \u0026#34;afternoon!\u0026#34;)) } Los decoradores se encuentran en algunos lenguajes de programación y en el mismo concepto en Go para que poder pasar datos a funciones.\nfunc sentenceFactory(mystring string) func(before, after string) string { return func(before, after string) string { return fmt.Sprintf (\u0026#34;%s %s %s\u0026#34;, before, mystring, after) } } Ejecución diferida Se puede usar la función defer en funciones para realizar una acción antes de devolver el valor o resolver la funcion, y si se escribe más de una, el orden en ejecución de estas acciones es la contraria, como en learnDefer:\nfunc learnDefer() (ok bool) { // instrucciones diferidas se ejecutan antes de que la función devuelva el resultado. defer fmt.Println (\u0026#34;deferred statements execute in reverse (LIFO) order.\u0026#34;) defer fmt.Println (\u0026#34;\\nThis line is being printed first because\u0026#34;) // defer se utiliza normalmente para cerrar un archivo después de abrirlo. return true } Interfaces Como ejemplo se define una función llamada Stringer que contiene una función llamada String; luego se define una estructura de dos dígitos de tipo int nombrados x y y.\ntype Stringer interface { String() string } type pair struct { x, y int } Aquí se define la función String como un pair, convirtiéndose en un pair para la implementación de la interfaz Stringer. La variable p a continuación se llama receptor (receiver). Observar cómo se accede a los campos de estructura de pair utilizando el nombre de la estructura seguido de un punto y luego el nombre del campo.\nfunc(p pair) String() string { return fmt.Sprintf (\u0026#34;(%d, %d)\u0026#34;, p.x, p.y) } Los puntos y comas se utilizan para crear un elemento de estructura (struct). Se usa la definición corta en el siguiente ejemplo para crear una variable llamada p y especificar su tipo en la estructura de pair.\nfunc learnInterfaces() { p := pair{3, 4} // llamar función String de pair fmt.Println(p.String()) // definir una variable como i del tipo Stringer interface previamente definida var i Stringer // esta igualdad es correcta, porque se aplica pair de Stringer i = p // se llama función String de la variable i de tipo Stringer y se obtiene // el mismo resultado que antes fmt.Println(i.String()) // al pasar las variables anteriores directamente a las funciones de impresión y salida fmt, // estas funciones llaman a la función String para imprimir la representación de la variable. */ // Las siguientes dos líneas dan el mismo resultado de impresión fmt.Println(p) fmt.Println(i) learnVariadicParams (\u0026#34;great\u0026#34;, \u0026#34;learning\u0026#34;, \u0026#34;here!\u0026#34;) } Múltiples entradas Es posible pasar variedad de variables a funciones sin un número definido de parámetros.\nfunc learnVariadicParams (myStrings... interface{}) { // la siguiente iteración recorre los elementos de entrada de datos de la función. for _, param: = range myStrings { fmt.Println(\u0026#34;param:\u0026#34;, param) } // se pasa la entrada de la función variadica como parámetro de otra función (para Sprintln) fmt.Println (\u0026#34;params:\u0026#34;, fmt.Sprintln(myStrings...)) learnErrorHandling() } Manejo de errores La palabra clave \u0026ldquo;ok\u0026rdquo; se utiliza para determinar si una sentencia es correcta. Si ocurre un error, se puede usar una variable err para conocer más detalles sobre el error.\nfunc learnErrorHandling() { m := map [int] string{3: \u0026#34;three\u0026#34;, 4: \u0026#34;four\u0026#34;} if x, ok := m[1]; !ok { // ok aquí será falso porque el número 1 no está en el mapa m fmt.Println(\u0026#34;no one there\u0026#34;) } else { // x será el valor en el mapa fmt.Print(x) } // aqui se intenta convertir valor de texto a número que resultará en un error, // se imprimen los detalles del error si err no es nil */ if _, err := strconv.Atoi(\u0026#34;non-int\u0026#34;); err != nil { fmt.Println(err) } learnConcurrency() } Ejecución simultánea Usando una función anterior para hacer una suma numérica a algunos números en conjunto. Se usa make para crear una variable sin especificar un valor para ella.\nfunc learnConcurrency() { // se crea una variable de tipo canal llamada c c := make(chan int) // creando tres funciones Go concurrentes. Los números se incrementarán simultáneamente // (en paralelo si el dispositivo está configurado para hacerlo). // todas las transmisiones irán al mismo canal // \u0026#34;go\u0026#34; aquí significa iniciar una nueva función go inc(0, c) go inc(10, c) go inc(-805, c) // luego hacer tres lecturas desde el mismo canal e imprimir los resultados. // no hay un orden de acceso de lectura desde el canal, y // también cuando el canal aparece a la derecha de la operación // \u0026lt;- significa que esta leyendo y recibiendo del canal fmt.Println(\u0026lt;-c, \u0026lt;-c, \u0026lt;-c) // nuevo canal con texto cs := make(chan string) // canal contiene canales de texto ccs := make(chan chan string) // enviar valor 84 al canal c go func() {c \u0026lt;- 84}() // enviar palabra al canal cs go func() {cs \u0026lt;- \u0026#34;wordy\u0026#34;}() // instrucción select es similar a la instrucción switch, // pero en cada caso contiene un proceso para un canal que // está listo para comunicarse. select { // valor recibido del canal se puede guardar en una variable case i := \u0026lt;-c: fmt.Printf(\u0026#34;it\u0026#39;s a %T\u0026#34;, i) case \u0026lt;-cs: fmt.Println(\u0026#34;it\u0026#39;s a string\u0026#34;) // canal vacío pero listo para comunicarse case \u0026lt;-ccs: fmt.Println(\u0026#34;didn\u0026#39;t happen.\u0026#34;) } } "},{"href":"https://gophers-latam.github.io/opensource/","title":"Open Source","body":"Software Open Source compartido en GitHub por Gophers LATAM.\n"},{"href":"https://gophers-latam.github.io/contacto/","title":"Contacto","body":"Medios de contacto con Gophers LATAM.\n"},{"href":"https://gophers-latam.github.io/colaboradores/","title":"Colaboradores","body":"Miembros públicos en github.com/gophers-latam\n"},{"href":"https://gophers-latam.github.io/biografia/","title":"Biografía","body":"Gophers LATAM es un esfuerzo conjunto por hacer una comunidad de programadores Golang en Español-Latino.\nLos inicios son desde el canal de YouTube de Tomás Lingotti, luego se adopto la idea del Discord el cual ha sido impulsado desde el mismo canal y en otros canales de YouTube, tales como el de Golandia. Compartido en otros medios como Facebook, Twitter y Linkedin. Y con apoyo desde los inicios de zeroidentidad.\nOtra forma en la que se ha adoptado hacer presencia es en Github.\n\u0026ndash; Todo lo mencionado surgió desde octubre del 2020.\n"},{"href":"https://gophers-latam.github.io/proyectos/awesomelatam/","title":"Awesome Latam","body":"Colección de contenidos y recursos principalmente en Español para desarrolladores de Golang\n"},{"href":"https://gophers-latam.github.io/proyectos/go-tour/","title":"Go Tour","body":"Para aquellos que aún no lo conocen, el \u0026lsquo;Tour de Go\u0026rsquo; representa una introducción excepcional al lenguaje de programación Go. Ofrece ejemplos interactivos y explicaciones detalladas, convirtiéndose en una herramienta invaluable para aquellos que desean aprender Go.\nComo comunidad, hemos realizado la traducción del sitio, permitiendo que cualquier persona de habla hispana tenga acceso a esta valiosa herramienta de aprendizaje.\nEstatus: Pendiente de aprobación por el sitio oficial de Go (https://go-review.googlesource.com/c/website/+/545855).\n"},{"href":"https://gophers-latam.github.io/proyectos/gokey/","title":"GoKey","body":"GoKey es un cache en memoria. El principal aspecto es guardar, leer y borrar entradas dentro del ciclo de vida de la goroutine main. Es decir, si deja de correr, los datos se pierden.\nEstatus: ETAPA 1 - libreria cliente\n"},{"href":"https://gophers-latam.github.io/proyectos/gopherbot/","title":"Gopher-Bot","body":"Bot de discord como mascota y utilidad de comandos en server discord.me/gophers-latam.\nEl bot se encuentra inactivo debido a que kintohub ya dejo de dar servicio. "}]}
\ No newline at end of file
+{"results":[{"href":"https://gophers-latam.github.io/posts/2024/01/desarrollo-con-go-en-neovim/","title":"Desarrollo con Go en Neovim","body":" Go con Neovim En este post vamos a ver cómo configurar desde cero Neovim y específicamente cómo personalizarlo para que nuestro desarrollo con Go sea altamente productivo.\nInstalación Lo primero que debemos de hacer es instalar Neovim.\nSi estamos en Windows, lo podemos hacer de la siguiente manera:\nwinget install Neovim.Neovim o también se puede realizar mediante gestores de paquetes externos como: Chocolatey o Scoop:\n# scoop scoop bucket add main scoop install neovim # chocolatey choco install neovim # (Podes usar `-y` para saltear automaticamente la confirmacion de mensajes). Y si estás en Linux, lo podés hacer de la siguiente manera, dependiendo de tu gestor de paquetes:\n# Arch sudo pacman -S neovim # Debian sudo apt-get install neovim # Fedora sudo dnf install -y neovim python3-neovim Para las demás distribuciones de Linux o para instalarlo de manera local, les dejo la documentación correspondiente.\nTener en cuenta que, dependiendo la distribución que se elija, será diferente la versión. Es decir, si descargamos Neovim en Ubuntu, vendrá con la versión 0.6 mientras que si se descarga en Manjaro, vendrán con la última versión estable (esto por la gestión de paquetes de cada distro).\nEs por esto que es siempre mejor descargar la última versión estable desde el código fuente, ya que nos aseguramos que nuestra versión sea la última y compatible con las últimas novedades de Neovim.\nGestión de carpetas Una vez instalado Neovim, vamos a generar nuestras carpetas.\nEn Linux, haremos lo siguiente en: ~/.config/nvim. Si nuestra carpeta no existe, la creamos.\nEn Windows, sera en: Local Disk (C:)/Users/tu-usuario/AppData/Local/nvim. Si nuestra carpeta no existe, la creamos.\nnvim/ ├── after/ │ └── plugin/ │ ├── tokyonight.lua │ └── telescope.lua ├── lua/ │ └── tu-nombre/ │ ├── init.lua │ ├── packer.lua │ ├── remap.lua │ └── set.lua ├── plugin/ │ └── packer_compiled.lua └── init.lua A continuación se explica para qué sirve cada carpeta.\nafter/plugin: Dentro de esta, creamos los .lua con el nombre del plugin que descarguemos para configurar como queramos nuestros plugins. En el arbol de referencia se ve los archivos tokyonight.lua y telescope.lua que nos sirven como ejemplo.\nlua/tu-nombre: Aquí, cambiaremos {tu-nombre} por tu nombre, en mi caso thiago, y dentro tendremos los archivos que nos servirán para descargar y setear nuestros atajos y configuraciones de Nvim.\nplugin: Esta carpeta debemos de generarla, pero su archivo (packer_compiled.lua) se genera automáticamente, en el ira toda nuestra configuración de Neovim. Es importante saber que no debemos de tocar este archivo.\ninit.lua: En este archivo, haremos el llamado de la carpeta \u0026ldquo;tu-nombre\u0026rdquo;, para que al iniciar se carguen automáticamente nuestras configuraciones.\nSi bien entraremos en detalle más adelante de cada archivo y configuración, está bueno saber el set up de nuestro editor de texto.\nPacker (Gestor de plugins) Ya con nuestras carpetas generadas, vamos a instalar Packer que será nuestro gestor de plugins para Neovim.\nEs cierto que este repositorio no se mantiene desde Agosto de 2023, y que muchos usuarios de Neovim están migrando a Lazy o Pckr (el sucesor de packer), pero para este post usaremos Packer, ya que sentará las bases de nuestro conocimiento para Neovim y luego podremos realizar otro post sobre la migración a Lazy (esto debido a que quien escribe, actualmente, no migró su gestor a otro 😅).\nPara instalar packer, debemos de hacerlo de la siguiente manera:\nInstalación en Unix, Linux.\ngit clone --depth 1 https://github.com/wbthomason/packer.nvim\\ ~/.local/share/nvim/site/pack/packer/start/packer.nvim Instalación en Windows PowerShell.\ngit clone https://github.com/wbthomason/packer.nvim \u0026#34;$env:LOCALAPPDATA\\nvim-data\\site\\pack\\packer\\start\\packer.nvim\u0026#34; Una vez instalado, iremos al siguiente path: .config/nvim/lua/tu-nombre/ e ingresaremos al archivo packer.lua en donde ingresaremos el siguiente código:\nreturn require(\u0026#39;packer\u0026#39;).startup(function(use) use \u0026#39;wbthomason/packer.nvim\u0026#39; end) Una vez hecho los cambios, haremos el siguiente comando en el modo normal: :so y enter. Y luego de esto haremos: :PackerInstall para instalar el nuevo paquete que agregamos.\nY ya que estamos realizando modificaciones, iremos a nvim/lua/tu-nombre/ y agregaremos los siguientes cambios en:\nnvim/lua/tu-nombre/init.lua require(\u0026#34;tu-nombre.set\u0026#34;) require(\u0026#34;tu-nombre.remap\u0026#34;) y en nuestro init.lua de nvim/init.lua: require(\u0026#34;tu-nombre\u0026#34;) Personalización ya con nuestra configuración básica, vamos a poner bonito nuestro editor de texto, ya que por default viene vacío.\nEn: lua/tu-nombre/set.lua, vamos a setear lo básico de nuestro editor de texto:\nvim.opt.nu = true -- Muestra el número de línea actual. vim.opt.smartindent = true -- Habilita el autoindentado inteligente. vim.opt.cursorline = true -- Resalta la línea en la que se encuentra el cursor. vim.opt.clipboard:append(\u0026#34;unnamedplus\u0026#34;) -- Configura el portapapeles para usar el registro \u0026#34;unnamedplus\u0026#34; (clipboard). vim.opt.termguicolors = true -- Habilita los colores de la terminal si es posible. vim.opt.tabstop = 4 vim.opt.softtabstop = 4 vim.opt.shiftwidth = 4 vim.opt.expandtab = true Y en lua/tu-nombre/remap.lua, vamos a realizar nuestros mapeos.\nPara ejecutar un plugin que instalamos se hace de la siguiente manera: :Plugin-a-Ejecutar\nPero esto es tedioso, por lo que en este archivo .lua, podemos configurarlo para que con ciertas combinaciones se ejecute el plugin que queramos.\nlocal keymap = vim.keymap -- Creamos esta variable para no estar constantemente escribiendo vim.keymap.set({}) local opts = { noremap = true, silent = true } -- Esto se hace para que nuestro atajo sea silencioso y no afecte tu vista. vim.g.mapleader = \u0026#34; \u0026#34; -- Seteamos la tecla espacio como lider. Esto nos servira mas adelante para mapear nuestros atajos. -- Usaremos este mapeo como ejemplo keymap.set(\u0026#34;n\u0026#34;, \u0026#34;\u0026lt;leader\u0026gt;q\u0026#34;, \u0026#34;:q\u0026lt;CR\u0026gt;\u0026#34;) -- Como bien sabemos, para salir de Nvim, se hace con :q. Entonces este mapeo, lo que nos permite es salir de nvim utilizando la combinacion de teclas: \u0026lt;leader\u0026gt; + q. -- \u0026lt;leader\u0026gt; lo seteamos mas arriba (vim.g.mapleader = \u0026#34; \u0026#34;), puede ser cualquier tecla y \u0026lt;CR\u0026gt; es un enter. -- Es lo mismo que hacer :q + enter, nada mas que lo asignamos a un mapeo y ejecutaremos esta funcion de forma facil y rapida. -- Ahora salir de Nvim no sera un problema. Para poder trabajar con temas de colores, lo haremos de la siguiente manera en: nvim/lua/tu-nombre/packer.lua\nreturn require(\u0026#39;packer\u0026#39;).startup(function(use) use \u0026#39;wbthomason/packer.nvim\u0026#39; -- Gestor de paquetes. use \u0026#39;folke/tokyonight.nvim\u0026#39; -- Esquema de colores. use(\u0026#34;nvim-treesitter/nvim-treesitter\u0026#34;, { run = \u0026#34;:TSUpdate\u0026#34; }) -- Nos provee un resaltado de colores en nuestro codigo. use({ \u0026#34;nvim-lualine/lualine.nvim\u0026#34;, -- Barra de estado. requires = { \u0026#34;kyazdani42/nvim-web-devicons\u0026#34;, opt = true }, }) use({ \u0026#34;nvim-tree/nvim-tree.lua\u0026#34;, -- Arbol de archivos. requires = { \u0026#34;nvim-tree/nvim-web-devicons\u0026#34;, }, }) use(\u0026#34;fatih/vim-go\u0026#34;) -- Para el desarrollo con Go. end) Una vez que tengamos los plugins que necesitemos, haremos lo que hicimos en pasos previos\n:so y enter y luego :PackerInstall para poder instarlos.\nUna vez instalados, debemos de ir a nvim/after/plugin/ y crear los archivos .lua para cada plugin que descargamos. Por ejemplo.\nnvim/after/plugin/lualine.nvim require(\u0026#39;lualine\u0026#39;).setup({ options = { theme = \u0026#34;auto\u0026#34; } }) nvim/after/plugin/nvim-treesitter.nvim require(\u0026#39;nvim-treesitter.configs\u0026#39;).setup({ ensure_installed = {\u0026#34;javascript\u0026#34;, \u0026#34;lua\u0026#34;, \u0026#34;json\u0026#34;, \u0026#34;html\u0026#34;, \u0026#34;css\u0026#34;, \u0026#34;typescript\u0026#34;, \u0026#34;markdown\u0026#34;, \u0026#34;go\u0026#34;, \u0026#34;python\u0026#34;}, sync_install = false, auto_install = true, highlight = {enable = true} }) Para que no se haga muy largo este post, haremos un video en el canal de YouTube de la comunidad para que sea más fácil y visual el uso de Nvim.\nEspero que este posts les sea de utilidad para aprender. Tambien les dejo mi configuración de Nvim en donde explico qué es, porque lo uso y todos los plugins que utilizo en mi día a día.\n"},{"href":"https://gophers-latam.github.io/posts/2023/12/manejo-de-memoria-101.-memoria-virtual-stack-y-heap/","title":"Manejo de memoria 101. Memoria virtual, Stack y Heap","body":" Puzzle. imagen de dominio público gentileza piqsels. https://www.piqsels.com/en/public-domain-photo-smyfi Que Go tiene un recolector de basura integrado lo hemos escuchado muchas veces. Significa que no tenemos que preocuparnos de liberar la memoria que nuestra aplicación usa, pero ¿Deberiamos entender el ciclo de uso de memoria de nuestras aplicaciones? ¿El recolector de basura nos da derecho a olvidar y usar y abusar de ese recurso?\nY, primero que nada ¿Que diablos es la memoria de la que tanto se habla?\nRenuncia de responsabilidades. No es trivial entender la forma en que los computadores trabajan. En aras de poder difundir intentaremos simplificar lo mas posible, en ocasiones, mas alla de lo recomendado. Muchos programadores hemos llegado a Go desde lenguajes de tipado débil, donde hemos tendido a mirar recursos como la memoria como si fueran gratuitos. Nada mas lejos de la verdad, como dice el viejo dicho No hay tal cosa como un almuerzo gratis y si queremos convertirnos en programadores mínimamente competentes debemos tener al menos una idea básica sobre la forma en que se manejan dichos recursos. He ahí la razón de este artículo.\nMemoria virtual Aquellos que ya tengan la escritura de algunos programas a su haber saben que cuando declaramos una variable, lo que estamos haciendo es asignar un identificador a una dirección de memoria en la que guardaremos datos (si nunca ha declarado una variable, hagase un favor y vaya al tour de go).\nMas o menos cuando hablamos de memoria todos pensamos en una grilla homogenea, con direcciones para acceder a cada casilla comodamente.\nPues bien, esa dirección de memoria no salió del aire por generación espontanea, existe físicamente de alguna forma en alguna parte.\nEn realidad, lo que llamamos memoria es una abstracción proporcionada por el sistema operativo, la cual oculta diferentes medios de almacenamiento.\nLos registros del procesador\nLa caché del procesador\nRAM\nArchivos en disco\nEtc.\nEn terminos generales, no sabemos en cual de estos medios de almacenamiento quedará almacenada nuestra variable. Solo sabemos que le hemos pedido memoria al sistema y que este nos la presentó adecuadamente para lograr nuestro objetivo. Claro, en aras de la eficiencia hay una gran probabilidad de que nuestro dato haya quedado guardado en RAM.\nEsta abstracción a la que hicimos referencia, es lo que llamamos memoria virtual, es administrada por el sistema operativo y es un recurso el cual debe ser solicitado.\nMemoria virtual es una abstracción que provee a cada proceso la ilusión de que tiene uso exclusivo sobre la memoria principal. Bryant, R. E. \u0026amp; O’Hallaron, D. R. (2016). Computer System: A Programmer’s Perspective (Third global edition). Pearson Education Limited.\nLa organización en forma de Celdas de memoria que nos es tan familiar es propia de la memoria virtual y como se imagina para que pueda funcionar se necesita una sofisticada interacción entre el sistema operativo y el hardware. Esta interacción se basa en un mapeo, direccionamiento o traslación entre las direcciones de la memoria virtual y el medio físico donde realmente se encuentre nuestro dato.\nCuando se ejecuta un programa, este tiene una visión uniforme de la memoria, la que llamamos Espacio de direcciones virtual, y dentro de este espacio hay dos áreas bien definidas que nos son de vital importancia.\nStack y Heap Stack El Stack es una región de la memoria que es localizada para cada hilo de ejecución de nuestros programas. En el contexto de Go, decimos que cada gorutina tiene su propio Stack. Su objetivo es contener variables locales, argumentos y valores de retorno de funciones, etc.\nCuando se invoca una función, se agrega una nueva capa en el Stack y cuando la función termina, esa capa se quita a su vez del Stack.\nLlamamos Localización/Allocation al proceso de reservar memoria para almacenar nuestros datos, y Deslocalización/Deallocation al proceso de liberarla una vez que ya no la necesitamos. El Stack tiene la ventaja de que permite acceder rápidamente a la memoria, ¡claro! porque los datos más recientes están siempre en la capa superior. Además, como cuando una función termina su ejecución, su capa asociada en el Stack se quita, ¡La memoria utilizada para los datos en esa capa se ve automáticamente deslocalizada!\nEl Stack empieza con espacio pre-localizado de un tamaño fijo, si el runtime detecta que se está quedando sin espacio, localiza más y como la memoría está localizada de antemano, guardar datos en el Stack es barato y automático.\nPara que una variable sea asignada en el Stack, deben cumplirse una serie de requisitos:\nTamaño fijo, conocido en tiempo de compilación\nEl runtime de Go debe ser capaz de determinar completamente su ciclo de vida\nSu tamaño no debe superar la capacidad máxima del Stack (mas las salvaguardas del runtime)\nEl Stack es rápido, localizar y dealocalizar en el es barato. Si estas y otras condiciones no son cumplidas, la variable escapará al Heap.\nHeap El Heap es el área del espacio de direcciones virtual que el runtime de Go solicita para almacenar los datos al ejecutar nuestro programa. El Heap crece dinámicamente y su objetivo es contener los datos que necesitamos persistan mas allá del tiempo de vida de una función o que son muy grandes para ser alojados en el stack.\nEl que nuestros datos escapen al Heap es costoso porque implica una localización, lo que significa que:\n1 Se verifica que el Heap tenga suficiente capacidad para el valor que almacenaremos en el.\n2 Si el punto 1 no se cumple, se debe solicitar más memoria al sistema operativo para el Heap. Se produce una System Call solicitando el recurso. En el mundo real este paso se realiza independientemente. El runtime monitorea constantemente el Heap y algunos algoritmos implementan un una meta, un límite de memoria, que una vez alcanzado o sobrepasado produce la solicitud de mas recursos al sistema operatvo.\n3 Se localiza la memoria en el Heap (por simplicidad incluyamos en este apartado la escritura de los datos que guardaremos).\n4 Se almacena en el Stack un puntero a la dirección de memoria inicial de la localización en el Heap.\nEl Heap es flexible, pero la flexibilidad viene con un costo ¡Todo esto es bastante trabajo para guardar un monton de datos! ¡Sea parsimonioso! Si, porque localizar en el Heap, si bien proporciona muchas ventajas, tiene un costo. Es por eso que en el ecosistema de Go usted encontrará librerías que se jactan de tener cero localizaciones, es decir, estan escritas tan cuidadosamente que no guardan datos en el Heap, sólo usan el Stack.\nEscapando al Heap Revisemos el siguiente código\nmain.go\npackage main func retString() string { retVal := \u0026#34;achu\u0026#34; return retVal } Hemos definido una función que devuelve un string. Construyamos un benchmark para que la podamos analizar.\nmain_test.go\npackage main import ( \u0026#34;testing\u0026#34; ) func Benchmark_retString(b *testing.B) { var a string b.ResetTimer() for i := 0; i \u0026lt;= b.N; i++ { a = retString() } b.StopTimer() b.Log(a) b.StartTimer() } Al ejecutar el benchmark veremos algo parecido al siguiente reporte\n$ go test -bench . -benchmem goos: linux goarch: amd64 pkg: exmem cpu: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz Benchmark_retString-16 1000000000 0.3356 ns/op 0 B/op 0 allocs/op Donde el benchmark nos informa con 0 allocs/op que han ocurrido 0 localizaciones al heap.\nReunamos más información. Agreguemos al comando el flag -gcflags \u0026quot;-m -m\u0026quot; que hará que el compilador realice un análisis de escape, el cual nos informará de movimientos de datos al heap.\n$ go test -gcflags \u0026#34;-m\u0026#34; -bench . -benchmem # exmem [exmem.test] ./main.go:3:6: can inline retString ./main_test.go:13:16: inlining call to retString ./main_test.go:7:26: leaking param: b ./main_test.go:17:7: ... argument does not escape ./main_test.go:17:8: a escapes to heap # exmem.test _testmain.go:37:6: can inline init.0 _testmain.go:45:24: inlining call to testing.MainStart _testmain.go:45:42: testdeps.TestDeps{} escapes to heap _testmain.go:45:24: \u0026amp;testing.M{...} escapes to heap goos: linux goarch: amd64 pkg: exmem cpu: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz Benchmark_retString-16 1000000000 0.3356 ns/op 0 B/op 0 allocs/op Continua reportandonos 0 localizaciones, pero ha agregado información interesante. Observe la siguiente línea en el reporte:\n./main_test.go:17:8: a escapes to heap Nos indica que la variable a escapa al Heap ¡Y nos dice el lugar exacto donde este escape ocurre!\nLa línea 17 de nuestro archivo de benchmark, precisamente donde pasamos la variable al logger.\nEsto demuestra que el escape no es producto de nuestro código pues el log de la variable está ahí solo como medio informativo y no es parte del mismo.\nConstruyamos otra función, esta vez una que devuelva un puntero a una variable local.\nfunc rePointerToString() *string { retVal := \u0026#34;achu\u0026#34; return \u0026amp;retVal } Y agreguemos el benchmark correspondiente.\nfunc Benchmark_retPointerToString(b *testing.B) { var a *string b.ResetTimer() for i := 0; i \u0026lt;= b.N; i++ { a = rePointerToString() } b.StopTimer() b.Log(a) b.StartTimer() } Al ejecutar el benchmark veremos un reporte parecido a lo que sigue:\ngoos: linux goarch: amd64 pkg: exmem cpu: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz Benchmark_retPointerToString Benchmark_retPointerToString-16 50917658\t24.86 ns/op\t16 B/op\t1 allocs/op PASS ok exmem\t1.292s ¡Una localización que reserva 16 bytes! Agreguemos un nivel más al análisis con -gcflags \u0026quot;-m\u0026quot;\n./main.go:3:6: can inline retString ./main.go:8:6: can inline rePointerToString ./main_test.go:13:16: inlining call to retString ./main_test.go:27:24: inlining call to rePointerToString ./main.go:9:2: moved to heap: retVal ./main_test.go:7:26: leaking param: b ./main_test.go:17:7: ... argument does not escape ./main_test.go:17:8: a escapes to heap ./main_test.go:21:35: leaking param: b ./main_test.go:27:24: moved to heap: retVal ./main_test.go:31:7: ... argument does not escape # exmem.test _testmain.go:39:6: can inline init.0 _testmain.go:47:24: inlining call to testing.MainStart _testmain.go:47:42: testdeps.TestDeps{} escapes to heap _testmain.go:47:24: \u0026amp;testing.M{...} escapes to heap goos: linux goarch: amd64 pkg: exmem cpu: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz Benchmark_retPointerToString Benchmark_retPointerToString-16 49800909 25.77 ns/op 16 B/op 1 allocs/op Otra vez podemos ver varias cosas interesantes:\n./main.go:9:2: moved to heap: retVal ... ./main_test.go:17:8: a escapes to heap ... ./main_test.go:27:24: moved to heap: retVal ... En el archivo main.go, donde definimos la función rePointerToString el análisis de escape nos informa que en la línea 9, donde definimos a la variable retVal como un string, el compilador ha movido la variable al Heap ¡Cuando aún no hemos devuelto su puntero! ¡Lo hacemos recien en la línea 10! ¡Claro! el compilador ha detectado que devolveremos un puntero al valor string almacenado en la variable local, por lo que ha determinado almacenar a la variable en el Heap directamente ¡Aun antes de que se produzca el retorno del puntero!\nHablar sobre memoria y otros temas relacionados con arquitectura de computadores es apasionante, pero es para nunca terminar.\nRecapitulando, hemos dado un recorrido introductorio a vuelo de pajaro sobre la memoria revisando al Stack y al Heap, con algunos ejemplos en código. Conocimos al flag -gcflags \u0026quot;-m\u0026quot; para agregar análisis de escape a nuestros tests y benchmarks.\nSi le gustó este artículo no olvide compartirlo.\n"},{"href":"https://gophers-latam.github.io/posts/2023/12/fuga-de-gorutinas/","title":"Fuga de gorutinas","body":" Fugas. imagen de dominio público gentileza pxfuel. https://www.pxfuel.com/en/free-photo-ojgpw Sabemos que las gorutinas son una de las mas importantes primitivas que Go pone a nuestra disposición para el manejo de concurrencia. Por eso se hace necesaria una forma de prevenir fugas de gorutinas.\nSi aun no empieza a estudiar concurrencia en Go ¡Le sugerimos ver este video de la comunidad antes de leer este artículo! Una fuga o leak de gorutinas es cuando nuestra aplicación crea gorutinas sin tener el cuidado de terminarlas correctamente.\nObservemos el siguiente ejemplo. Seguramente reconocerá el problema, en este caso estamos enviando información por un canal y no tenemos a nadie que consuma dicho canal.\npackage main import ( \u0026#34;fmt\u0026#34; \u0026#34;math/rand\u0026#34; \u0026#34;runtime\u0026#34; \u0026#34;time\u0026#34; ) func send() int { n := rand.Intn(1000) time.Sleep(200 * time.Millisecond) return n } func submit() int { ch := make(chan int) go func() { ch \u0026lt;- send() }() go func() { ch \u0026lt;- send() }() go func() { ch \u0026lt;- send() }() go func() { ch \u0026lt;- send() }() return \u0026lt;-ch } func submitAll() { for i := 0; i \u0026lt; 5; i++ { submit() } } func main() { submitAll() fmt.Printf(\u0026#34;número de gorutinas: %d\\n\u0026#34;, runtime.NumGoroutine()) } Si ejecutamos este programa veremos lo siguiente:\n$ go run main.go número de gorutinas: 16 Imprime número de gorutinas: 16 ¿Por que razón? Porque el contenido del loop se itera 4 veces y en cada iteración engendra 4 gorutinas en la función submit. Ingenuamente podriamos estar esperando que al salir del ámbito de la función submit las gorutinas se hubiesen cerrado ¡Pero no es así! ¡Siguen corriendo al final de su proceso como lo demuestra la impresión!\nUna fuga o leak de gorutinas es cuando nuestra aplicación crea gorutinas sin tener el cuidado de terminarlas correctamente. Ahora bien, si nuestra aplicación terminara en este punto, no habría problema alguno, pues al acabar su ejecución ya es responsabilidad del sistema operativo realizar las labores de limpieza. Pero muchas veces usamos Go para construir aplicaciones que se ejecutan continuamente sin parar y que se espera que no se detengan, como servicios, apis, etc. En este tipo de aplicaciones, un escenario como el presentado en el ejemplo es insostenible.\nGo reserva una cantidad de memoria específica inicial para que las gorutinas usen como su stack, si bien esta cantidad puede variar de versión en versión, la cantidad actual se puede revisar en el repositorio de GO\nEste stack puede ir creciendo según el proceso que se ejecute dentro de la gorutina.\nEl problema Entonces, ¿Que pasará si nuestra aplicación sufre de fuga de gorutinas y engendra 100000 de ellas durante un periódo de un año sin terminarlas correctamente?\nPues asumiendo optimistamente que el proceso que se ejecuta dentro de nuestras gorutinas fugadas devuelven correctamente la memoria, y que el stack asignado a cada una de ellas sigue teniendo un tamaño de 2kB, tendriamos para ese momento cerca de 200MB de memoria usada por la aplicación que no podrán ser recuperados por el recolector de basura ¡Porque las gorutinas todavía están ejecutandose! ¡Porque nunca nos aseguramos de terminarlas correctamente!\nSi no cuidamos de terminar correctamente las gorutinas que nuestra aplicación engendra, corremos el riesgo de enfrentar Out Of Memory Errors Si ejecutamos nuestra aplicación en algún tipo de contenedor o máquina virtual con un límite duro de memoría, esto puede llegar a ocasionar out of memory errors\n¿Que podemos hacer?\nPreviniendo fugas de gorutinas Inevitablemente debemos aprender y convertirnos en expertos en el modelo de memoria de Go y en su modelo de concurrencia. Esto es de vital importancia, pues de la misma forma que un carpintero es responsable de usar de forma segura su sierra circular, taladro y otros implementos, nosotros como programadores somos responsables de usar correctamente las herramientas de nuestro oficio.\nEn esto cae la construcción de tests y benchmarks y el uso profilactico de herramientas de perfilado como pprof asegurandonos de que las pruebas se realicen por un periodo de tiempo conveniente, pues no es lo mismo perfilar un servicio el mismo día en que lo lanzamos a correr, que dos meses después.\nOtra herramienta muy útil es goleak del equipo de Uber Go, que presenta una forma muy simple de testear que nuestras gorutinas se cierren correctamente.\nSe usa de la siguiente forma:\n1 Debemos importarla a nuestro proyecto $ go get -u go.uber.org/goleak\n2 Debemos construir un test que incluya el flujo completo de nuestras gorutinas. Usaremos el mismo ejemplo anterior\nImportamos la utilidad y nos aseguramos de invocarla usando defer para que se garantice su ejecución al final de nuestro proceso.\npackage main import ( \u0026#34;testing\u0026#34; \u0026#34;go.uber.org/goleak\u0026#34; ) func TestGorutineLeak(t *testing.T) { defer goleak.VerifyNone(t) for i := 0; i \u0026lt; 4; i++ { submitAll() } } ¡Y listo! Al ejecutar el test, si goleak detecta fugas de gorutinas, el test fallará\n$ go test ./... === RUN TestGorutineLeak /home/jacobopus/projects/go/goru/main_test.go:15: found unexpected goroutines: [Goroutine 7 in state chan send, with goru.submit.func1 on top of the stack: goru.submit.func1() /home/jacobopus/projects/go/goru/main.go:19 +0x30 created by goru.submit in goroutine 6 /home/jacobopus/projects/go/goru/main.go:19 +0x66 ] --- FAIL: TestGorutineLeak (4.46s) FAIL Puede revisar la documentación de goleak para descubrir otras formas de uso.\nNo olvide compartir este articulo si fue de su agrado.\n"},{"href":"https://gophers-latam.github.io/posts/2023/10/el-tour-de-go-ahora-en-espa%C3%B1ol/","title":"El tour de Go ahora en Español","body":" Tour de Go en Español ¡Logramos algo increíble como comunidad! La traducción del tour de Go al español. Estamos emocionados de compartir con todos ustedes el increíble logro que hemos alcanzado juntos: la completa traducción del tour de Go al español.\nEste proyecto fue un esfuerzo colaborativo en el que nuestra comunidad contribuyó con su tiempo y conocimiento para hacer que esta herramienta esté disponible para toda la comunidad hispanohablante. ¡El resultado es asombroso!\n¿Qué es El Tour de Go? 👩‍💻👨‍💻 Para aquellos que aún no lo conocen, el \u0026ldquo;Tour de Go\u0026rdquo; es una excelente introducción al lenguaje de programación Go. Proporciona ejemplos interactivos y explicaciones detalladas, lo que lo convierte en una herramienta invaluable para aprender Go.\nEl poder de la colaboración 👥 La clave de este logro fue la colaboración. Cada uno de nosotros aportó con sus habilidades y conocimientos para llevar a cabo esta traducción. Desde los que realizaron las primeras traducciones hasta aquellos que revisaron y pulieron cada detalle, cada uno de ustedes fue fundamental.\n¿Qué significa esto para la comunidad? 💡 La traducción del tour al español no solo significa que más personas tendrán acceso a esta valiosa herramienta, sino que también fortalece nuestra comunidad y nos posiciona como un grupo que puede lograr grandes cosas cuando trabajamos juntos.\n¿Qué sigue? 🛠️ Nuestro trabajo no termina aquí. Continuaremos buscando maneras de contribuir y crecer como comunidad. Si tienes ideas o proyectos en mente, ¡no dudes en compartirlas!\nUna vez más, felicitaciones a todos los que participaron en este proyecto. ¡Han demostrado el increíble poder de la comunidad de Gophers Latam!\n¡Sigamos construyendo juntos! 🚀 Tour de Go Link del repositorio: https://github.com/gophers-latam/go-tour-es\nLink profesional sobre la comunidad: https://es.linkedin.com/posts/thiago-mowszet_github-gophers-latamgo-tour-es-traducci%C3%B3n-activity-7118450478593536000-JlrR\n"},{"href":"https://gophers-latam.github.io/posts/2023/03/handlers-con-timeout/","title":"Handlers Con Timeout","body":" go handlers En algunas oportunidades, vamos a necesitar un comportamiento muy determinístico en nuestras APIs, ya sea porque el negocio así lo requiere o los clientes. Tal vez, un comportamiento que se mantenga alejado de cualquier sorpresa, puede ser el máximo de duración que le queremos dejar como ventana para que un respuesta sea entregada, en caso de excederlo, ahora si como el título lo dice, devolvemos un timeout\u0026hellip; pero, qué es un timeout?\nEn principio sabemos que contamos con 2 estados para representarlo, pero no se parecen mucho ya que están en centenas distintas, unos es 408 request timeout y el otro es 504 Gateway timeout. Si leemos un poco las especificaciones, ninguno de los dos nos calza justo para lo que queremos, el 408 nos dice que el cliente \u0026ldquo;se tardó demasiado para enviar su request\u0026rdquo;, desde la RFC dice lo siguiente:\nThe client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time.\nY para su contraparte del lado del servidor:\nThe server was acting as a gateway or proxy and did not receive a timely response from the upstream server.\nEntonces, para la responder la pregunta, concluimos que un timeout es que esperamos demasiado por algo, y no sucedió, ademas, lo consideramos un error.\nCómo hacemos nuestras funciones de Timeout? En los lenguajes de programación modernos, encontramos built-in algunas formas de manejar estos casos de uso. En Golang, por ejemplo el paquete context tiene constructores para crear uno que expire y se cancele después de cierto tiempo.\nDentro del paquete net/http también nos encontramos con muchos timeouts como por ejemplo en la struct http.Client para hacer requests y http.Server es otra que tampoco se queda afuera de tener este tipo de configuración.\nPor ahora, tenemos: context, http.Client y Server, servidores TCP y UDP, etc. Podemos resumir que siempre que haya una conexión hacia fuera (ya sea cliente o servidor) vamos a poder configurar un timeout.\nCómo nos sirven en los web handlers? Antes, debemos aclarar que es un middleware, en cualquier lenguaje, ya que es un concepto y no una implementación específica de Golang.\nEntonces, decimos que son funciones con la misma firma que un handler (o controlador web), que recibe los mismos parámetros para operar como una petición HTTP. Al ser iguales, nos permite ejecutarlo previamente de una forma sencilla y pre-ejecutar operaciones que nos ayuden a nuestro negocio. Un claro ejemplo son validaciones de token JWT, agregar request ID unicos, sumarle datos al contexto (esto si es mas estilo gopher). En nuestro caso, vamos a tener un middleware que se encargue de reemplazar el contexto, por otro que tenga un timeout, para que no tarde mas de tanto tiempo y si no, falla. Nos va a ayudar a garantizar un tiempo de respuesta de máxima, por las buenas o por las malas.\nLo llevamos a código Como middleware, podemos usar uno que ya existe y está dentro del paquete http, es http.Timeout y dentro de su firma, vamos a pasarle un http.Handler, el tiempo de espera que vamos a soportar y por último (este no me gusta mucho) un mensaje como string, donde nos quita un poco de flexibilidad, a mi entender, []byte nos daría un espectro mas amplio a la hora de retornar los valores.\nPodemos implementarlo como un wrapper general a todo el multiplexer y que todos ejecuten el middleware, este tiene como ventaja que escribimos una sola vez, pero perdemos granularidad. func main() { mux := http.NewServeMux() mux.HandleFunc(\u0026#34;/\u0026#34;, func(w http.ResponseWriter, r *http.Request) { //.... }) muxWithMiddleware := http.TimeoutHandler(mux, time.Second*5, \u0026#34;timeout!\u0026#34;) log.Fatal(http.ListenAndServe(\u0026#34;:8080\u0026#34;, muxWithMiddleware)) } Por último, tenemos otro camino, para tener un control espercífico en cada handler que expongamos. func main() { mux := http.NewServeMux() helloHandler := http.TimeoutHandler(wrapHandlerFunc(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(\u0026#34;hello with timeout!\u0026#34;)) })), time.Second*5, \u0026#34;timeout\u0026#34;) mux.Handle(\u0026#34;/\u0026#34;, helloHandler) } func wrapHandlerFunc(handler http.Handler) http.Handler { wrapped := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set(\u0026#34;Content-Type\u0026#34;, \u0026#34;application/json\u0026#34;) handler.ServeHTTP(w, r) }) return wrapped } Conclusiones Vemos la flexibilidad que tenemos para exponer funciones en un servior web que tenemos en Golang. Siempre nos da muchas facilidades y opciones, a su vez, puede ser un poco confuso porque no sabemos bien cual usar. Como pequeño consejo, no nos fritemos la cabeza pensando y comparando, tan solo elijamos una con un análisis superficial y despues nos queda el aprendizaje.\nPara cerrar el tema técnico, estamos re-utilizando una funcion de la stdlib de Go, por lo que no es necesario que nostros pensemos esa lógica, también, muchos de los Frameworks web como Echo, Gin y Fiber (seguramente entre varios otros) ya traen sus middleware de timeout y es de una implementacion muy similar a la que acabamos de ver.\nEspero que les haya gustado la explicación! nos vemos dentro de poco y cualquier tema que quieran que tratemos lo pueden dejar en comentarios.\n"},{"href":"https://gophers-latam.github.io/posts/2022/08/intro-go-mistakes-okno/","title":"Intro Go Mistakes Okno","body":" okno Se comparte el concepto o contexto de algunos errores basicos con su definición acompañado de ejemplo y solución.\nIndice: Código y organización del proyecto Código y organización del proyecto - Sombreado de variable (shadowing) no deseado La parte de una aplicación donde un enlace de nombre es válido. En Go, un nombre de variable declarado en un bloque se puede volver a declarar en un bloque interno. Este principio, llamado sombreado de variable, es propenso a errores.\nEjemplo:\nvar client *http.Client if tracing { client, err := createClientWithTracing() if err != nil { return err } log.Println(client) } else { client, err := createDefaultClient() if err != nil { return err } log.Println(client) } 1 Declarar una variable client 2 Crear un cliente HTTP con tracing habilitado, la variable client está sombreada en este bloque 3 Crear un cliente HTTP predeterminado, la variable client también se sombrea en este bloque Como resultado, de este ejemplo, la variable externa siempre será nula.\nSolución:\nLa primera opción es usar variables temporales en los bloques internos:\nvar client *http.Client if tracing { c, err := createClientWithTracing() if err != nil { return err } client = c } else { // Same logic } 1 Crear una variable temporal c 2 Asignar esta variable temporal a client Otra opción es usar el operador de asignación (=) en los bloques internos para asignar directamente los resultados de la función a la variable. Sin embargo, requiere crear una variable de error ya que el operador de asignación solo funciona si ya se ha declarado un nombre de variable:\nvar client *http.Client var err error if tracing { client, err = createClientWithTracing() if err != nil { return err } } else { // Same logic } 1 Declarar una variable de error 2 Usar operador de asignación para asignar el *http.Client devuelto a la variable client directamente - Código anidado innecesario Un aspecto crítico de la legibilidad es el número de niveles anidados. Un código se califica como legible en función de múltiples criterios, como el nombrado, la consistencia, el formato, etc. Un código legible requerirá menos esfuerzo cognitivo para mantener un modelo mental; por lo tanto, será más fácil de leer y mantener.\nEjemplo:\nTiempo o dificultad para entender la siguiente función a detalle.\nfunc join(s1, s2 string, max int) (string, error) { if s1 == \u0026#34;\u0026#34; { return \u0026#34;\u0026#34;, errors.New(\u0026#34;s1 is empty\u0026#34;) } else { if s2 == \u0026#34;\u0026#34; { return \u0026#34;\u0026#34;, errors.New(\u0026#34;s2 is empty\u0026#34;) } else { concat, err := concatenate(s1, s2) if err != nil { return \u0026#34;\u0026#34;, err } else { if len(concat) \u0026gt; max { return concat[:max], nil } else { return concat, nil } } } } } func concatenate(s1 string, s2 string) (string, error) { // ... } Solución:\nHacer la tarea de aplicar legibilidad y consistencia sobre la misma función, implementandola de manera diferente:\nfunc join(s1, s2 string, max int) (string, error) { if s1 == \u0026#34;\u0026#34; { return \u0026#34;\u0026#34;, errors.New(\u0026#34;s1 is empty\u0026#34;) } if s2 == \u0026#34;\u0026#34; { return \u0026#34;\u0026#34;, errors.New(\u0026#34;s2 is empty\u0026#34;) } concat, err := concatenate(s1, s2) if err != nil { return \u0026#34;\u0026#34;, err } if len(concat) \u0026gt; max { return concat[:max], nil } return concat, nil } func concatenate(s1 string, s2 string) (string, error) { // ... } El resultado para requerir menos carga cognitiva. - Mal uso de las funciones init En principio init es una función que no toma argumentos y no devuelve ningún resultado (una función func()). Cuando se inicializa un paquete, se evalúan todas las declaraciones de constantes y variables del paquete. El principal problema reside cuando se ha creado un flujo de uso que se vuelve dificil de entender o seguir y por falta de entendimiento se provocan errores no manejados que se volveran dificiles de mitigar o controlar.\nEjemplo:\nOlvidar o no haber entendido el sentido o punto de entrada para ejecuion de init.\npackage main import \u0026#34;fmt\u0026#34; var a = func() int { fmt.Println(\u0026#34;var\u0026#34;) return 0 }() func init() { fmt.Println(\u0026#34;init\u0026#34;) } func main() { fmt.Println(\u0026#34;main\u0026#34;) } Salida\n1: var 2: init 3: main Ejemplo de flujo usando Redis en base de codigo personal.\nSolución:\nHay criterios en sentido idiomatico como:\nEvitar incluir funciones init en codigo que sera probado con paquete de testing.\nNo hacer que sean de ambito global a menos que sea realmente requerido.\nEvitar usar para conexiones a base de datos.\nInvestigar situaciones en las que pueden ser útiles, como definir una configuración estática. De lo contrario, y en la mayoría de los casos, manejar las inicializaciones a través de funciones personalizadas.\nEbook recomendado: 100 Go Mistakes Que trata a fondo algunos errores sobre: Tipos de datos, Estructuras de control, Strings en detalle, Funciones y métodos, Manejo de errores, Concurrencia: Fundamentos y Práctica, Librería estándar, Pruebas y Optimizaciones\n"},{"href":"https://gophers-latam.github.io/posts/2021/12/ecosistema-lenguage-go/","title":"Ecosistema lenguage Go","body":" json to go Go, también conocido como Golang, es un lenguaje de programación de tipado estático desarrollado por Robert Griesemer, Rob Pike y Ken Thompson en Google.\nGo es sintácticamente similar a C, pero viene con seguridad de memoria, recolección de basura, tipificación estructural y sincronización al estilo CSP.\nHay dos implementaciones principales:\nEl paquete de alojamiento de Google que se dirige a múltiples sistemas operativos, dispositivos móviles y WebAssembly.\ngccgo (un front) y GCC\nGo es expresivo, conciso, limpio y eficiente. Los mecanismos simultáneos facilitan la escritura de aplicaciones que aprovechan al máximo las máquinas en red de varios núcleos, mientras que el sistema más nuevo permite crear aplicaciones modulares y flexibles. Compila código máquina con bastante rapidez, pero tiene la conveniencia de la recolección de basura y el poder de reflejar el tiempo de ejecución. - Un lenguaje rápido, bien tipado y bien proporcionado que actúa como un lenguaje interpretado dinámico.\nNada hace que un programador se emocione más que descubrir un nuevo lenguaje de programación. Al examinar el estado actual del software y hardware informático, podemos ver por qué tenemos que cambiar a un nuevo lenguaje como Go. Durante la última década, la potencia de procesamiento en bruto ha aumentado ligeramente y el rendimiento de la frecuencia de la CPU se ha mantenido casi constante durante una década.\nGo, se libero cuando los procesadores de varios núcleos ya estaban disponibles. Es por eso que Go se hizo pensando en la coordinación. Sus mecanismos síncronos facilitan la escritura de aplicaciones que utilizan más sistemas multinúcleo y en red. Si bien el nuevo tipo de sistema Go hace posible construir aplicaciones modulares flexibles, en lugar de centrarse en teorías, en métodos del mundo real para construir aplicaciones de próxima generación en la nube, así como computación avanzada y computación distribuidas.\nHistórico Go es un lenguaje de programación procedimental que se lanzó en 2009 como lenguaje de programación de código abierto. Actualmente se utiliza en varios sistemas operativos de Google. El Go Compiler es compatible con Linux, Mac OS, Windows y una variedad de sistemas operativos BSD como FreeBSD. En términos de arquitectura de procesador, la arquitectura X86, la arquitectura X64, la arquitectura ARM y la arquitectura Power específica de IBM también son compatibles con Go.\nArquitectura Lingüística Go tiene muchas herramientas poderosas de análisis estático. Uno de ellos es go fmt, que diseña su código basándose en el estilo Go propuesto. Esto puede eliminar muchos comentarios en un proyecto normal y alentar a su equipo a concentrarse en el código. Lenguaje de programación desarrollado y compilado de forma nativa, que pertenece principalmente a la familia de lenguajes C en términos de sintaxis básica.\nComo C y C++, está compilado en código de máquina, por lo que no necesitamos entornos como CLR y JVM para ejecutar programas Go. Esto ayuda especialmente al compilar programas grandes. Lenguaje simple y minimalista con diseño original de Go para en lugar del clásico Thread a goroutines. En Go, el límite de tamaño de pila mínimo se elimina de 4 KB a 8 KB cuando se crea una goroutine.\nDiseño Go está influenciado por C, pero con un mayor énfasis en la simplicidad y la seguridad. Esto incluye:\nPatrones de adopción de sintaxis y entorno que son más comunes en lenguajes dinámicos: Declaración de variable corta opcional e introducción inicial por inferencia de tipo.\nEdición rápida.\nAdministración de paquetes remotos (go download) y documentación de paquetes en línea.\nEnfoques distintivos para problemas específicos.\nSincronización inicial: procesos de estilo (Gurvin), canales y expresiones selectivas.\nUn sistema de interfaz en lugar de herencia virtual e incrustación de tipo en lugar de la herencia no virtual.\nUn kit de herramientas que, de forma predeterminada, crea binarios de interfaz nativa sin dependencias externas.\nLa tendencia a preservar las propiedades del lenguaje es lo suficientemente simple como para mantener en calam la cabeza de un programador, en parte eliminando características que son comunes a lenguajes similares.\nGo es Back o Front? El código Go se puede ejecutar usando goper.js en el navegador. Pero el hecho es que la mayoría de los desarrolladores recurren a los lenguajes de programación Front y JavaScript para desarrollar su lado del cliente. Go es más preferido como lenguaje de respaldo y ofrece un alto rendimiento para el desarrollo simultáneo de aplicaciones de servidor.\nAlgunas aplicaciones populares desarrolladas en Go Algunos de los proyectos de código abierto en Go son:\nCaddy: servidor web HTTP 2 de código abierto con capacidad HTTPS automática\nCockroachDB: una base de datos SQL de código abierto, escalable y compatible\nDocker: incluye un conjunto de herramientas de implementación de Linux.\nEthereum: implementación de Go-Ethereum, máquina de bloqueo de máquina virtual, Ethereum virtual para criptomoneda Ether\nHugo: un generador de sitios estáticos\nInfluxDB: base de datos de código abierto para series de datos de alto acceso con requisitos de alto rendimiento\nInterPlanetary File System: un contenido y un protocolo de direccionamiento de medios punto a punto.\nJuju: una herramienta de evaluación de servicios de Canonical, paquetes de Ubuntu Linux.\nKubernetes: sistema de gestión de contenedores\nLightning Network: una red de bitcoins para transacciones rápidas de bitcoins.\nMattermost: un sistema de chat en equipo.\nOpenShift: una plataforma de computación en la nube proporcionada por Red Hat como servicio.\nSnappy: un administrador de paquetes para Ubuntu Touch desarrollado por Canonical.\nSyncthing: software de sincronización de archivos cliente/servidor de código abierto.\nTerraform: una herramienta de código abierto para la infraestructura multimedia en la nube proporcionada por HashiCorp.\nEmpresas y sitios notables que han utilizado GO (generalmente junto con otros lenguajes, no exclusivamente) Cacoo: para renderizar paneles de usuario y microservicios usando Go y gRPC.\nChango: una empresa de publicidad que utiliza sistemas de precios en tiempo real.\nCloud Foundry: una plataforma como servicio.\nCloudFlare: se utiliza para el proxy de codificación Delta Railgun, su servicio de DNS distribuido, así como herramientas para encriptación, registro, procesamiento de flujo y acceso a sitios SPDY.\nCoreOS: un sistema operativo basado en Linux que utiliza el repositorio Docker y el repositorio rkt.\nDropbox: que ha migrado algunos de sus componentes vitales de Python a Go.\nEthereum: una moneda digital\nGoogle: se utiliza para muchos proyectos, incluido el servidor de descargas (dl.google.com).\nHyperledger Fabric: un proyecto de código abierto único.\nMongoDB: una herramienta para administrar instancias de MongoDB\nNetflix: se utiliza para dos partes de la arquitectura de su servidor.\nNovartis: para sistema de inventario interno\nNutanix: se utiliza para una variedad de microservicios en su empresa Cloud OS.\nPlug.dj: un sitio web interactivo relacionado con la transmisión de música social en línea.\nSendGrid: un boulder, servicio de entrega de correo electrónico y servicio de gestión de transacciones.\nSoundCloud: se utiliza para \u0026ldquo;docenas de sistemas\u0026rdquo;.\nEmpalme: se utiliza para todo el backend (API y analizadores) en su plataforma de colaboración musical en línea.\nThoughtWorks: Algunas herramientas y aplicaciones para entrega continua y mensajería instantánea (CoyIM).\nTwitch.tv: para el sistema de chat basado en IRC (migración desde Python).\nUber: para manejar grandes volúmenes de consultas basadas en geovallas\nGo Features Go compila código como lenguajes de bajo nivel como C++/C. Esto significa que funciona casi tan bien como lenguajes de bajo nivel. También utiliza la recolección de basura para recolectar y eliminar objetos.\nEl gráfico siguente muestra que Go es casi tan eficiente como C++/C, mientras mantiene la sintaxis simple como Ruby, Python y otros lenguajes. Esta es una situación en la que todos ganan para los humanos y los procesadores! El alto rendimiento como C++/C y Java proporciona una sincronización altamente eficiente para codificar en términos divertidos como Python y Perl. El software optimizado puede ejecutarse en hardware más barato y lento, como los dispositivos IoT, y generalmente tiene un mayor impacto en la experiencia del usuario final. El modelo de memoria Go agrega una nueva regla para enviar y recibir canales de búfer para indicar explícitamente que un canal de búfer puede usarse como un simple spammer.\nDescripción general de las características principales del lenguaje:\nCompilación: Go genera compilaciones binarias para sus aplicaciones con todas las dependencias. No se requiere instalación de traductor o runtime.\nRecolección de basura: Para recolectar desperdicios de baja latencia, opta por una administración automática de memoria que sea eficiente y sincrónica. La gestión de la memoria es intencionadamente más fácil que C y C++. Los objetos dedicados recolectan basura de forma dinámica.\nSeguro: Go es un lenguaje de tipado estático que admite la seguridad de tipos. El compilador detecta los errores antes de la ejecución.\nSintaxis similar a C: La sintaxis Go recuerda a la familia C, pero con solo 25 palabras clave simples, es fácil de analizar sin tablas/símbolos de información de tipo y un diseño de notificación similar a Pascal.\nVarios paradigmas: Go admite varios patrones de programación, incluida la programación esencial, orientada a objetos (OOP) y la programación funcional.\nLibrería estándar: Go tiene una potente librería estándar de paquetes para respaldar el desarrollo de aplicaciones Go.\nDocumentación sencilla: GoDoc es una herramienta de análisis de código estático que genera documentos estándar simplificados directamente desde el código.\nSoporte de pruebas naturalmente: Soporte de prueba integrado en la librería estándar. Sin necesidad de dependencia adicional Si tiene un archivo llamado thing.go, escriba sus pruebas en otro archivo llamado thing_test.go y ejecute \u0026ldquo;go test\u0026rdquo;.\nGo Tools La distribución principal de Go incluye herramientas para crear, probar y analizar código:\ngo build: crea un binario usando solo sus archivos fuente.\ngo test: se utiliza para pruebas unitarias y microbenchmarks.\ngo fmt: se utiliza para formatear el código.\ngo get: se utiliza para recuperar e instalar paquetes remotos.\ngo vet: un analizador estático que busca posibles vulnerabilidades o errores en el código.\ngo run: un atajo para construir y ejecutar código directamente.\ngo doc: para mostrar documentos o enviarlos a través de HTTP\ngo rename: se utiliza para renombrar variables, funciones, etc. en tipo seguro.\ngo generate: un método estándar para llamar a un generador de código\nTambién incluye soporte de depuración y perfiles, herramientas de medición de tiempo de ejecución. El ecosistema de herramientas de terceros se ha agregado a la distribución estándar, incluido gocode, que permite completar automáticamente el código en muchos editores de texto. goimports (por un miembro del equipo de Go) que automáticamente elimina o agrega paquetes según sea necesario, y errcheck, que detecta errores de código y puede ignorarlos. Hay complementos para agregar soporte de idioma en algunos editores de texto. Hay varios IDE disponibles, incluidos LiteIDE y el \u0026ldquo;Go IDE multiplataforma\u0026rdquo; y GoLand.\nAplicaciones del lenguaje Go está diseñado específicamente como lenguaje de programación para grandes sistemas distribuidos y servidores de red altamente escalables. En este sentido, reemplaza a C++ y Java en la pila de software de Google. Muchos equipos buscan crear nuevos servidores en Go. Algunos incluso están migrando bases de código existentes. Algunas de las tecnologías de Google que utiliza a diario tienen componentes escritos en Go.\nDado que este es un lenguaje de programación relativamente nuevo, muchos preguntan para qué es adecuado.\nUn vistazo a algunos de sus beneficios:\nIdeal para el desarrollo web\nExcelente para scripts de línea de comandos\nSe puede utilizar para aplicaciones de servidor de red.\nSe puede utilizar para el desarrollo de front-end.\nLos desarrolladores disfrutan usando Go porque tiene un entorno de desarrollo completo, y aprender Go es muy fácil, incluso para desarrolladores sin experiencia. Una de las razones de esto se debe al gran ecosistema de herramientas, por lo que es muy útil para proyectos grandes y conjuntos. Esto lo convierte en una excelente opción para programar software propietario. Si se está buscando más beneficios, Go fue creado y es mantenido por Google, que tiene una de las infraestructuras de nube más importantes del mundo y puede ser a gran escala.\nData Science Es una ciencia multidisciplinaria que utiliza métodos, procesos, algoritmos y sistemas científicos para extraer conocimientos e ideas de datos estructurados y no estructurados. La ciencia de datos es el concepto de combinar estadísticas, análisis de datos, aprendizaje automático y métodos relacionados para comprender y analizar fenómenos reales con datos. Extrae técnicas y teorías que han surgido de muchos campos de las matemáticas, la estadística, la informática y la ciencia de la información. El ganador del premio Turing, Jim Gray, ve la ciencia de datos como el \u0026ldquo;cuarto modelo\u0026rdquo; de la ciencia (experimental, teórico, computacional y ahora basado en datos) y afirma que \u0026ldquo;todo lo relacionado con la ciencia está cambiando debido al impacto de la tecnología de la información\u0026rdquo;.\nEn la actualidad, a menudo se usa indistintamente con conceptos anteriores, como análisis empresarial, inteligencia empresarial, modelado de previsión y estadísticas. Si bien muchos programas académicos ahora tienen un título en ciencia de datos, no existe un consenso sobre la definición del contenido curricular apropiado. Sin embargo, muchos proyectos de ciencia de datos y Big Data no han podido lograr resultados útiles, a menudo debido a la falta de gestión y utilización de recursos.\n« Go demuestra cada vez pruebas más rápidas, codificación fácil en lenguajes de programación concurrentes altamente eficientes. Por lo general, es la próxima generación de ciencia de datos, aprendizaje automático e inteligencia artificial, porque existe un gran equilibrio entre la productividad y la retención de código. Muchos prototipos de científicos de datos, que luego son transferidos a producción por otra persona, deja que Go haga ambas cosas. »\n"},{"href":"https://gophers-latam.github.io/posts/2021/08/go-talks/","title":"Go Talks","body":" talks Este post contiene charlas de Go que se pueden leer siguiendo los vinculos de cada título listado.\n2019 playground-v3.slide: Playground v3 2017 state-of-go-may.slide\nexporting-go\nstate-of-go-aug\n2016 refactor.article: Codebase Refactoring (with help from Go)\napplicative.slide: Program your next server in Go\nasm.slide: The Design of the Go Assembler\nstate-of-go.slide: The State of Go\ntoken.slide: Stacks of Tokens\nprototype-your-design\n2015 dynamic-tools.slide: Go Dynamic Tools\ngo-for-java-programmers.slide: Go for Java Programmers\ngo4cpp.slide: Go for C++ developers\ngofmt-cn.slide: gofmt 的文化演变\ngofmt-en.slide: The Cultural Evolution of gofmt\ngogo.slide: Go in Go\ngophercon-go-on-mobile.slide: Go on Mobile\ngophercon-goevolution.slide: The Evolution of Go\ngotham-grpc.slide: gRPC Go\nhow-go-was-made.slide: How Go was made\njson.slide: JSON, interfaces, and go generate\nkeeping-up.slide: Keeping up with the Gophers\nsimplicity-is-complicated.slide: Simplicity is Complicated\nstate-of-go.slide: The State of Go\ntricks.slide: Stupid Gopher Tricks\n2014 c2go.slide: Go, from C to Go\ncamlistore.slide: - Camlistore: Android, ARM, App Engine, anywhere.\ncompiling.slide: - Go: Easy to Read, Hard to Compile\ndroidcon.slide: Go on Android\ngo1.3.slide: Toward Go 1.3\ngo4gophers.slide: Go for gophers\ngo4java.slide: Go for Javaneros (Javaïstes?)\ngocon-tokyo.slide: - Go: 90% Perfect, 100% of the time.\ngotham-context.slide: Cancelation, Context, and Plumbing\ngothamgo-android.slide: Go on Android\nhammers.slide: Gophers With Hammers\nhellogophers.slide: Hello, Gophers!\nnames.slide: What\u0026rsquo;s in a name?\norganizeio.slide: Organizing Go code\nplayground.slide: Inside the Go playground\nreadability.slide: When in Go, do as Gophers do\nresearch.slide: The Research Problems of Implementing Go\nresearch2.slide: More Research Problems of Implementing Go\nstate-of-go.slide: The State of Go\nstate-of-the-gopher.slide: The State of the Gopher (Oct)\nstatic-analysis.slide: Static analysis tools\ntaste.slide: A Taste of Go\ntesting.slide: Testing Techniques\n2013 advconc.slide: Advanced Go Concurrency Patterns\nbestpractices.slide: Twelve Go Best Practices\ndistsys.slide: Go, for Distributed Systems\ngo-sreops.slide: Go Language for Ops and Site Reliability Engineering\ngo1.1.slide: What\u0026rsquo;s new in Go 1.1\ngo4python.slide: Go for Pythonistas\nhighperf.slide: High Performance Apps with Go on App Engine\noscon-dl.slide: dl.google.com: Powered by Go\n2012 10things.slide: 10 things you (probably) don\u0026rsquo;t know about Go\nchat.slide: - Go: code that grows with grace\nconcurrency.slide: Go Concurrency Patterns\ngo-docs.slide: Go docs\ngo1.slide: The Path to Go 1\ngoforc.slide: Go for C programmers\ninsidepresent.slide: Inside the \u0026ldquo;present\u0026rdquo; tool\nsimple.slide: - Go: a simple programming environment\nsplash.slide: Go at Google\ntutorial.slide: Get started with Go\nwaza.slide: Concurrency is not Parallelism\nzen.slide: Go and the Zen of Python\n2011 lex.slide: Lexical Scanning in Go 2010 ExpressivenessOfGo-2010\ngo_talk-20100112\ngo_talk-20100121\ngo_talk-20100323\ngofrontend-gcc-summit-2010\n2009 go_talk-20091030 "},{"href":"https://gophers-latam.github.io/posts/2021/06/conversi%C3%B3n-json-a-go/","title":"Conversión JSON a Go","body":" json to go Uno de los formatos de datos que se encuentra con mucha frecuencia en programación, principalmente web, es JavaScript Object Notation (JSON).\nCuando se recibe datos en formato JSON de representación, debe convertirse a un formato que sea fácil de manipular en el programa en Go. Hay algunas herramientas en línea que permiten convertir fuente JSON directamente en estructuras Go, aunque haciendo una simple búsqueda google.com/search?q=json+to+go se ve varidad de resultados, las destacadas o pioneras son:\nJSON-to-Go - mholt.github.io/json-to-go/\nTransform - transform.tools/json-to-go\nJson2Struct - json2struct.mervine.net/\nPor último como extensión de navegador para mejor accesibilidad existe json to go para Chrome.\n"},{"href":"https://gophers-latam.github.io/posts/2021/05/golang-implementaci%C3%B3n-del-almacenamiento-en-cach%C3%A9/","title":"Golang: Implementación del almacenamiento en caché","body":" go cache El almacenamiento en caché de datos en una aplicación web a veces es necesario para evitar solicitar datos estáticos de una base de datos o un servicio externo una y otra vez. Go no proporciona ningún paquete integrado en la librería estándar para almacenar en caché las respuestas, pero lo admite a través de paquetes externos creados por la comunidad.\nHay una serie de paquetes, como github.com/coocood/freecache, github.com/patrickmn/go-cache, github.com/eko/gocache y github.com/etcd-io/etcd (gRPC) que pueden ayudar a implementar el almacenamiento en caché. Por parte de la comunidad de Gophers LATAM se busca crear algo relacionado: github.com/gophers-latam/GoKey\nPara este post se estará usando github.com/patrickmn/go-cache para implementar un ejemplo de uso.\nEjemplo: Primero crear un directorio para el código fuente de prueba e inicializar un go module. [go mod init cache-example]\nLuego crear archivo .go, donde se hará un caché por medio de la librería y se completará con datos sobre el arranque del servidor, de la siguiente manera:\npackage main import ( \u0026#34;fmt\u0026#34; \u0026#34;log\u0026#34; \u0026#34;net/http\u0026#34; \u0026#34;time\u0026#34; \u0026#34;github.com/patrickmn/go-cache\u0026#34; ) const ( CONN_PORT = \u0026#34;8080\u0026#34; ) var newCache *cache.Cache func init() { newCache = cache.New(5*time.Minute, 10*time.Minute) newCache.Set(\u0026#34;gophers\u0026#34;, \u0026#34;gophers latam\u0026#34;, cache.DefaultExpiration) } func getFromCache(w http.ResponseWriter, r *http.Request) { gophers, found := newCache.Get(\u0026#34;gophers\u0026#34;) if found { log.Print(\u0026#34;Key encontrada en caché con valor, como : \u0026#34;, gophers.(string)) fmt.Fprintf(w, \u0026#34;Hola \u0026#34;+gophers.(string)) } else { log.Print(\u0026#34;Key no encontrada en caché : \u0026#34;, \u0026#34;gophers\u0026#34;) fmt.Fprintf(w, \u0026#34;Key no encontrada en caché\u0026#34;) } } func main() { http.HandleFunc(\u0026#34;/\u0026#34;, getFromCache) err := http.ListenAndServe(\u0026#34;:\u0026#34;+CONN_PORT, nil) if err != nil { log.Fatal(\u0026#34;error al iniciar el servidor http : \u0026#34;, err) return } } Ejecutar el código. Como funciona: Una vez iniciado, el servidor HTTP comenzará a escuchar localmente en el puerto 8080. Al inicio, la clave con el nombre gophers con un valor como gophers latam se agregará a la caché.\nAl navegar por http://localhost:8080/ se leerá un valor de key de la caché y lo agregará a Hola como se muestra en la siguiente captura de pantalla:\nLog en terminal:\nSe ha especificado el tiempo de caducidad de los datos de la caché en el programa como 5 minutos, lo que significa que la clave que se ha creado en la caché al iniciar el servidor no estará allí después de 5 minutos. Por lo tanto, acceder a la misma URL nuevamente después de 5 minutos devolverá que la clave no es encontrada en la caché del servidor, de la siguiente manera:\nUsando var newCache *cache.Cache, se declara una caché privada.\nSe actualiza la función init() donde se crea un caché con 5 minutos de tiempo de vencimiento y 10 minutos de intervalo de limpieza, y se agrega un elemento a caché con una clave como gophers con su valor como gophers latam y su valor de vencimiento como 0, lo que significa que se quiere usar el tiempo de vencimiento predeterminado de la caché.\nPara usarse se define el controlador getFromCache donde se recupera el valor de una clave en caché. Si se encuentra, se escribe en respuesta HTTP, de lo contrario, se escribe el mensaje Key no encontrada en caché.\n"},{"href":"https://gophers-latam.github.io/posts/2021/05/golang-init-func/","title":"Golang: Init func","body":" init func Cada programa en Go debe tener un paquete main con una función main para ser ejecutado. Sin embargo, esto impone algunas limitaciones para determinadas soluciones, como las librerías. Imagina que importamos una librería a nuestro código.\nUna librería no está diseñada para ser ejecutada, ofrece estructuras de datos, métodos, funciones, etc. Es probable que las librerías ni siquiera tengan un paquete main. Si esta librería requiere alguna configuración inicial antes de ser invocada (inicializar variables, detectar el sistema operativo, etc.) parece imposible.\nGo define las funciones init que se ejecutan una vez por paquete. Cuando importamos un paquete, el tiempo de ejecución (runtime) de Go sigue este orden:\nInicializar los paquetes importados de forma recursiva. Inicializar y asignar valores a las variables. Ejecutar las funciones de init. Ejemplos: 1. - En el resultado para el código de ejemplo se muestra cómo la inicialización sigue el orden descrito anteriormente. La función xSetter se invoca primero, seguida de init y la función main.\npackage main import \u0026#34;fmt\u0026#34; var x = xSetter() func xSetter() int { fmt.Println(\u0026#34;xSetter\u0026#34;) return 42 } func init() { fmt.Println(\u0026#34;Init function\u0026#34;) } func main() { fmt.Println(\u0026#34;Este es el main\u0026#34;) } Salida en ejecución: La función init no tiene argumentos ni devuelve ningún valor. Un paquete puede tener varias funciones init y no se pueden invocar desde ninguna parte del código.\nGo no permite importar un paquete si no se usa dentro del código. Sin embargo, es posible que solo nos interese ejecutar las funciones init de un paquete. Esto es lo que Go llama los efectos secundarios de un paquete (side effects pkg). Por lo general, esto se hace en paquetes que realizan alguna operación de arranque o registro. La instrucción especial import _ solo llama a las funciones init de un paquete que no requiere su uso dentro del código.\n2. - Ejemplo usando import _ : importado el paquete \u0026ldquo;a\u0026rdquo; para utilizar sus efectos secundarios. Observar que este paquete tiene dos funciones init que se ejecutan antes del init del paquete de importación. [go mod init ejemplo2]\nejemplo2/main.go\npackage main import ( \u0026#34;fmt\u0026#34; _ \u0026#34;ejemplo2/a\u0026#34; ) func init() { fmt.Println(\u0026#34;Init desde mi programa\u0026#34;) } func main() { fmt.Println(\u0026#34;Mi programa\u0026#34;) } ejemplo2/a/a.go\npackage a import \u0026#34;fmt\u0026#34; func init() { fmt.Println(\u0026#34;Init 1 desde paquete a\u0026#34;) } func init() { fmt.Println(\u0026#34;Init 2 desde paquete a\u0026#34;) } Salida en ejecución: "},{"href":"https://gophers-latam.github.io/posts/2021/04/golang-referencia-esencial-go-modules/","title":"Golang: Referencia esencial Go modules","body":" Go Modules Esta es una hoja de trucos esenciales, no una referencia oficial. Con el fin de que sea conciso, se omitieron aspectos menos frecuentes, dado que este sitio desde su repositorio esta abierto a cambios de contribuidores en la comunidad de Gophers LATAM cualquiera puede hacer cambios que mejoren este contenido.\nInicio rápido Gestión de dependencias go get -d github.com/path/to/module # agregar o actualizar dep (-v log verboso) go get -d github.com/dep/two/v2@v2.1.0 # usar una versión específica go get -d github.com/dep/commit@branch # usar una rama específica go get -d -u ./... # actualizar módulos utilizados en subdirectorios go get -d github.com/dep/legacy@none # eliminar dep Comandos útiles go mod tidy # organizar y limpiar go.mod and go.sum go mod download # descargar deps en caché de módulos go mod init github.com/path/to/module # inicializar nuevo módulo go mod why -m github.com/path/to/module # por qué el módulo es una dependencia? go install github.com/path/to/bin@latest # construir e instalar binario Anatomía del go.mod // ruta de importación de Go con lugar donde se aloja el módulo module github.com/my/library go 1.16 // versión utilizada para desarrollar módulo (usar nuevas funciones de lenguaje) require ( github.com/dep/one v1.0.0 // v2 y posteriores tienen versión principal en ruta del módulo github.com/dep/two/v2 v2.3.0 // \u0026#34;pseudo-versión\u0026#34; que se refiere a un commit y no a una versión etiquetada. github.com/dep/other v0.0.0-20180523231146-b3f5c0f6e5f1 github.com/dep/legacy v2.0.0+incompatible // \u0026#34;incompatible\u0026#34; significa que el paquete aún no se ha migrado a nuevos módulos de Go ) exclude github.com/dep/legacy v1.9.2 // evitar que se use una versión de módulo específica replace github.com/dep/one =\u0026gt; github.com/fork/one // reemplazar este módulo con este otro Selección de versión mínima (MVS) Para crear un programa, Go necesita saber exactamente qué dependencias necesita y qué versión usar.\nGo utiliza MVS como una forma sencilla y predecible de decidir qué versión utilizar.\nFunciona así:\nEl módulo desde el que está ejecutando es el \u0026ldquo;módulo main\u0026rdquo;\nEncuentra todas las dependencias que necesita el módulo principal (de forma recursiva, usando los archivos go.mod de las dependencias)\nPara cada dependencia, usar la mayor versión que cualquier go.mod haya especificado explícitamente\nEjemplo: En este ejemplo, el módulo principal depende de A 1.0 y B 2.1.\nDado que B 2.1 depende de A 1.1, esta es la versión de A que se utilizará.\nDado que se usa A 1.1, también en C 1.1.\nLa lista final de dependencias es:\nA 1.1 B 2.1 C 1.1 Fuentes: Referencia oficial: https://golang.org/ref/mod\nVersión del post original: https://encore.dev/guide/go.mod\n"},{"href":"https://gophers-latam.github.io/posts/2021/04/golang-la-interfaz-vac%C3%ADa/","title":"Golang: La interfaz vacía","body":" Interface type Explicación breve sobre el tipo interfaz vacia y nula.\nSe define una interfaz vacía como interface{}, y puede contener un valor de cualquier tipo:\nvar i interface{} i = \u0026#34;hola gophers\u0026#34; fmt.Println(i) Si se necesita probar si una interfaz es de cierto tipo, se usa una aserción de tipo:\nvar i interface{} i = \u0026#34;hola gophers\u0026#34; s, ok := i.(string) if !ok { fmt.Println(\u0026#34;s is not type string\u0026#34;) } fmt.Println(s) En el ejemplo anterior, i es un tipo string, por lo que el segundo valor de retorno de la aserción de tipo es verdadero (ok) y s contiene el valor por debajo de este. Si hubiera sido de otro tipo, como un int, entonces el ok habría sido falso y s habría sido el valor cero del tipo que se estaba tratando de afirmar, es decir, 0.\nInterfaz nula Una interfaz en Go es esencialmente una tupla que contiene el tipo y el valor subyacentes. Para que una interfaz se considere nula, tanto el tipo como el valor deben ser nulos (nil). Ejemplo:\npackage main import ( \u0026#34;fmt\u0026#34; ) func main() { var i interface{} fmt.Println(i == nil) fmt.Printf(\u0026#34;%T, %v\\n\u0026#34;, i, i) var s *string fmt.Println(\u0026#34;s == nil:\u0026#34;, s == nil) i = s fmt.Println(\u0026#34;i == nil:\u0026#34;, i == nil) fmt.Printf(\u0026#34;%T, %v\\n\u0026#34;, i, i) Salida:\ntrue \u0026lt;nil\u0026gt;, \u0026lt;nil\u0026gt; s == nil: true i == nil: false *string, \u0026lt;nil\u0026gt; Observar que la variable s es nil, pero cuando se establece la interfaz i en s, se verifica si i es nil, i no se considera nil. Esto se debe a que la interfaz tiene un tipo concreto por debajo establecido y las interfaces solo son nulas cuando tanto el tipo concreto como el valor son nulos.\n"},{"href":"https://gophers-latam.github.io/search/","title":"Búsqueda","body":""},{"href":"https://gophers-latam.github.io/posts/2021/04/golang-mantener-actualizado-el-sdk/","title":"Golang: Mantener actualizado el SDK","body":" Update Go Como ocurre con todos los lenguajes de programación, hay actualizaciones periódicas de las herramientas de desarrollo de Go. El SDK Go son binarios nativos que no dependen de un tiempo de ejecución independiente, por lo que no hay que preocuparse de que la actualización del entorno de desarrollo pueda hacer que los programas actualmente implementados fallen. Puede tenerse programas compilados con diferentes versiones de Go ejecutándose simultáneamente en la misma computadora o máquina virtual.\nDesde Go 1.2, ha habido una nueva versión importante aproximadamente cada seis meses. También hay versiones menores con correcciones de errores y seguridad que se publican según sea necesario. Dados los rápidos ciclos de desarrollo y el compromiso del equipo de Go con la compatibilidad con versiones anteriores, las versiones de Go tienden a ser incrementales en lugar de expansivas. La promesa de compatibilidad de Go es una descripción detallada de cómo el equipo de Go planea evitar romper el código de Go. Dice que no habrá cambios retrógrados en el lenguaje o la librería estándar para cualquier versión de Go que comience con 1, a menos que el cambio sea necesario para un error o corrección de seguridad. Sin embargo, puede haber (y ha habido) cambios incompatibles con versiones anteriores en los indicadores o la funcionalidad de los comandos go.\nA pesar de estas garantías de compatibilidad con versiones anteriores, los errores ocurren, por lo que es natural querer asegurarse de que una nueva versión no rompa los programas personales ya hechos. Una opción es instalar un entorno Go secundario. Por ejemplo, si actualmente se está ejecutando la versión 1.15.2 y se quiere probar la versión 1.16.3, debe usarse los siguientes comandos:\ngo get golang.org/dl/go.1.16.3 go1.16.3 download Luego se puede usar el comando go1.16.3 en lugar del comando go para ver si la versión 1.16.3 funciona para los programas ya hechos anteriormente con la nueva versión de Go:\ngo1.16.3 build Una vez que se haya validado que el código funciona, puede eliminarse el entorno secundario buscando el GOROOT, eliminándolo y luego eliminando el binario del directorio $GOPATH/bin. A continuación, las indicaciones de cómo hacerlo en Mac OS, Linux y BSD respectivamente:\ngo1.16.3 env GOROOT /Users/gobook/sdk/go1.16.3 rm -rf $(go1.16.3 env GOROOT) rm $(go env GOPATH)/bin/go1.16.3 Cuando se está listo para actualizar las herramientas de desarrollo de Go instaladas en la computadora, los usuarios de Mac y Windows tienen la ruta más fácil. Aquellos que instalaron con brew o chocolatey pueden usar esas herramientas para actualizar. Aquellos que usaron los instaladores en golang.org/dl pueden descargar el último instalador, que elimina la versión anterior cuando se instala la nueva.\nLos usuarios de Linux y BSD en general deben descargar la última versión, mover la versión anterior a un directorio de respaldo, expandir la nueva versión y luego eliminar la versión anterior, algo así:\nmv /usr/local/go /usr/local/old-go tar -C /usr/local -xzf go1.16.3.linux-amd64.tar.gz rm -rf /usr/local/old-go Como nota final, igual en cada versión que sale en el canal del Discord #📰fuente-noticias se comparte automáticamente del canal de Twitter oficial como obtener la nueva versión.\n"},{"href":"https://gophers-latam.github.io/posts/2021/04/golang-resumen-reglas/","title":"Golang: Resumen reglas","body":" Go Police El lenguaje de programación Go fue creado para hacer el trabajo fácilmente.\nGo tiene conceptos similares a los lenguajes imperativos y el tipado estático.\nTambién es rápido en la compilación, rápido de ejecutar e implementar. Grande y complejo.\nEn este post, se explican conceptos básicos de Go tratando algunos conceptos o reglas importantes.\nLos principales temas tratados son los siguientes:\nEscribir comentarios. Librerías e importación. Funciones. Tipos de datos. Valores de retorno con nombre. Variables y memoria. Control de sentencias. Generar funciones. Ejecución diferida. Interfaces. Múltiples entradas. Manejo de errores. Ejecución simultánea. Escribir comentarios: Para escribir un comentario de una línea\n// comentario de una sola línea Escribir un comentario con más de una línea\n/* comentario de multi-línea */ Librerías e importación: Cada archivo de código fuente comienza con la palabra clave package. La palabra clave main se utiliza para identificar el archivo como un archivo operativo, no como una librería.\npackage main Para importar un paquete de la librería estándar, terceros o personal al archivo, usamos la instrucción import de la siguiente manera:\nimport ( \u0026#34;fmt\u0026#34; // paquete en la librería estándar \u0026#34;io/ioutil\u0026#34; // se aplican funciones de E/S m \u0026#34;math\u0026#34; // usando la letra m para acortar o hacer alias del nombre de la librería de funciones matemáticas \u0026#34;net/http\u0026#34; // web server \u0026#34;os\u0026#34; // funciones a nivel del sistema operativo, como el manejo de archivos \u0026#34;strconv\u0026#34; // conversiones de texto ) Funciones: Las funciones se definen mediante la palabra func seguida del nombre de la función.\nLa función main es privada y es la entrada al archivo ejecutable del programa (Go usa llaves ornamentadas {} para definir partes / bloques).\nfunc main() { // salida de texto en la unidad main en stdout (salida estandar) con Println de fmt (stdlib pkg) fmt.Println (\u0026#34;Hello world!\u0026#34;) // llamar a una función del paquete actual beyondHello() } Las funciones necesitan paréntesis que reciben parámetros, e incluso en ausencia de parámetros, se requieren paréntesis.\nfunc beyondHello() { // declaración de variable (la variable debe declararse antes de usarse) var x int // dar valor a la variable x = 3 // definición corta usando := incluye definición de variable, especificando su tipo y dándole valor y := 4 // una función que devuelve dos valores separados sum, prod := learnMultiple (x, y) // imprimir salida de forma sencilla y directa fmt.Println (\u0026#34;sum:\u0026#34;, sum, \u0026#34;prod:\u0026#34;, prod) learnTypes() } La definición de función puede tener múltiples coeficientes y valores de retorno. Por ejemplo, learnMultiple toma los coeficientes x, y \u0026hellip; y devuelve dos valores de sum y prod de tipo Int.\nfunc learnMultiple (x, y int) (sum, prod int) { // separar los valores devueltos con una coma regular return x + y, x * y } Tipos de datos: func learnTypes() { // las declaraciones cortas generalmente cumplen el propósito deseado // definir una variable de texto usando comillas dobles str := \u0026#34;Learn Go!\u0026#34; // definir una variable de texto con comillas simples s2 := `A \u0026#34;raw\u0026#34; string literal can include line breaks.` // definir variable tipo runa que es otro nombre para el tipo int32 que contiene unicode g := \u0026#39;Σ\u0026#39; // float f := 3.14195 // definición de número complejo (Complex) c := 3 + 4i // definir variables usando var var u uint = 7 // número natural (entero positivo) var pi float32 = 22. / 7 // un decimal de 32 bits // definición corta byte (es otro nombre para uint8) n := byte (\u0026#39;\\n\u0026#39;) // arrays tienen un tamaño fijo, y son fijos en momento de compilación // definir un array int de 4 elementos con un valor inicial de cero var a4 [4] int // definir un array de 3 elementos con valores 3, 1 y 5 a3 := [...] int {3, 1, 5} Go ofrece un tipo de datos llamado Slices. Los Slices entendibles como \u0026ldquo;rebanadas\u0026rdquo;, \u0026ldquo;porciones\u0026rdquo;, \u0026ldquo;segmentos\u0026rdquo; tienen un tamaño dinámico. Las matrices (array) y los segmentos (slice) tienen ventajas, pero los casos de uso de los segmentos son más comunes. La siguiente instrucción define un segmento de tipo int\n// observar la diferencia entre el array y la declaración del slice, donde cuando // el slice está definido no hay un número que determine su tamaño s3: = [] int {4, 5, 9} // definir un tipo int con cuatro elementos con valores cero s4: = make ([] int, 4) // solo definir, y no hay selección var d2 [] [] float64 // método para convertir el tipo de texto en slice bs: = [] byte (\u0026#34;a slice\u0026#34;) Por la naturaleza de los slice dinámicos, es posible agregar nuevos elementos usando la función append incorporada. Primero se pasa el slice al que queremos agregar y luego los elementos que queremos agregar.\ns := [] int {1, 2, 3} s = append (s, 4, 5, 6) // se imprimirá un slice con el siguiente contenido [1 2 3 4 5 6] fmt.Println (s) Para agregar un slice a otro slice, pasamos los dos slices en la función en lugar de pasar elementos individuales, y siguiendo el segundo slice con tres puntos.\ns = append (s, [] int {7, 8, 9} ...) // se imprimirá un slice con el siguiente contenido [1 2 3 4 5 6 7 8 9] fmt.Println (s) La siguiente instrucción define las variables p y q como punteros en dos variables de tipo int que contienen dos valores devueltos por la función learnMemory:\np, q := learnMemory() // tema de reglas por ver Cuando un asterisco precede a un cursor, significa el valor de la variable a la que se refiere el cursor, como en el siguiente ejemplo los valores de las dos variables devueltas por la función learnMemory:\nfmt.Println (*p, *q) Los mapas (maps) en Go son arrays dinámicos y modificables que son similares al tipo de diccionario o hash en otros lenguajes.\n// aquí un mapa cuya clave es tipo texto y los valores de los elementos numéricos. m: = map [string] int {\u0026#34;three\u0026#34;: 3, \u0026#34;four\u0026#34;: 4} m [\u0026#34;one\u0026#34;] = 1 Las variables no utilizadas son errores. El subrayado, guion bajo, operador blanco o Blank Identifier de la siguiente manera hace usar la variable pero ignora valores al mismo tiempo:\n_, _, _, _, _, _, _, _, _, _ = str, s2, g, f, u, pi, n, a3, s4, bs Valores de retorno con nombre: A diferencia de otros lenguajes, las funciones pueden tener valores de retorno con nombre. Donde el nombre se devuelve al valor de la función en la línea de la definición de la función, esta característica permite regresar fácilmente desde cualquier punto de la función además del uso de la palabra return solo sin mencionar nada después:\nfunc learnNamedReturns (x, y int) (z int) { z = x * y // aquí implícitamente significa devolver el valor de la variable z return } Nota: El lenguaje Go se basa en gran medida en la recolección de basura. Go tiene indicadores pero no cálculos (puede confundir un cursor vacío, pero no puede aumentar el cursor). Tener cuidado con valores de retorno de nil pointer reference.\nVariables y memoria: Las variables p y q a continuación son indicadores del tipo int y representan valores de retorno en la función. Cuando se define, los cursores están vacíos; sin embargo, el uso de la función incorporada new hace que el valor de la variable numérica p se refiera a cero, y por lo tanto ocupa espacio en la memoria; es decir, p ya no está vacío.\nfunc learnMemory() (p, q* int) { p = new(int) // definir un slice de 20 elementos como una sola unidad en la memoria. s := make([] int, 20) // dar valor a un elemento s[3] = 7 // definir una nueva variable local a nivel de función r := -2 // devolver dos valores de la función, que son direcciones de memoria // para las variables s y r, respectivamente. return \u0026amp;s[3], \u0026amp;r } func expensiveComputation() float64 { return m.Exp (10) } Control de sentencias Las sentencias condicionales requieren corchetes ornamentados y no requieren paréntesis.\nfunc learnFlowControl() { if true {fmt.Println (\u0026#34;told ya\u0026#34; ) } if false { // Rusters. } else { // Gophers. } Usar la instrucción switch si se necesita escribir más de una secuencia condicional.\nx := 42.0 switch x { case 0: case 1: case 42: case 43: default: } Como sentencia condicional, la cláusula for no toma paréntesis. Las variables definidas en la cláusula for son visibles a nivel de la sentencia.\nfor x: = 0; x \u0026lt;3; x ++ { fmt.Println (\u0026#34;iteration\u0026#34;, x) } La instrucción for es la única instrucción de iteración en el lenguaje Go y tiene otra formas, de la siguiente manera:\n// repetición infinita for { // break para detener la repetición break // continue para ir a la siguiente iteración continue } Se puede utilizar el range para pasar elementos de array, slice, text string, map, channel.\nEl range de canal (channel) devuelve un valor, y dos valores cuando se usa en slice, array, text string, o map.\n// ejemplo: for key, value := range map [string] int {\u0026#34;one\u0026#34;: 1, \u0026#34;two\u0026#34;: 2, \u0026#34;three\u0026#34;: 3} { // imprimir el valor de cada elemento del mapa fmt.Printf (\u0026#34;key =% s, value =% d \\n\u0026#34;, key, value) } Usar el guión bajo (_) contra valor de retorno en la clave si solo se desea el valor, de la siguiente manera:\nfor _, name: = range [] string {\u0026#34;Bob\u0026#34;, \u0026#34;Bill\u0026#34;, \u0026#34;Joe\u0026#34;} { fmt.Printf (\u0026#34;Hello,% s \\n\u0026#34;, name) } Se puede usar la declaración corta con la sentencia condicional para que se defina una variable y luego se verifique en la sentencia de condición.\nPor ejemplo se define una variable y, se le da un valor y luego se coloca la condición de la sentencia para que estén separadas por un punto y coma.\nif y := expensiveComputation(); y \u0026gt; x { x = y } Se puede definir funciones anónimas falsas directamente en el código.\nxBig := func() bool { // x:= 42 que fue declarada antes donde de menciona la sentencia switch return x \u0026gt; 10000 } x = 99999 // la función xBig ahora devuelve el valor verdadero fmt.Println (\u0026#34;xBig:\u0026#34;, xBig()) x = 1.3e3 // Después de modificar el valor de x a 1.3e3 que es igual a 1300 (es decir, mayor que 1000) // la función xBig devuelve falso fmt.Println (\u0026#34;xBig:\u0026#34;, xBig()) Además de lo anterior, es posible definir función fantasma y llamarla en la misma línea y pasarla a otra función siempre que se llame directamente y el tipo de resultado sea consistente con lo esperado en el parámetro de la función.\nfmt.Println (\u0026#34;Add + double two numbers:\u0026#34;, func (a, b int) int { return (a + b) * 2 } (10, 2)) goto love love: learnFunctionFactory() // Una función que devuelve una función learnDefer() // Dormir learnInterfaces() // Trabajar con interfaces } Generar funciones Se puede tratar las funciones como objetos separados. Por ejemplo, crear una función y el valor de retorno es otra.\nfunc learnFunctionFactory() { Los dos métodos siguientes para imprimir la oración son iguales, pero el segundo método es más claro, más legible y común.\nfmt.Println(sentenceFactory (\u0026#34;summer\u0026#34;) (\u0026#34;A beautiful\u0026#34;, \u0026#34;day!\u0026#34;)) d: = sentenceFactory (\u0026#34;summer\u0026#34;) fmt.Println(d (\u0026#34;A beautiful\u0026#34;, \u0026#34;day!\u0026#34;)) fmt.Println(d (\u0026#34;A lazy\u0026#34;, \u0026#34;afternoon!\u0026#34;)) } Los decoradores se encuentran en algunos lenguajes de programación y en el mismo concepto en Go para que poder pasar datos a funciones.\nfunc sentenceFactory(mystring string) func(before, after string) string { return func(before, after string) string { return fmt.Sprintf (\u0026#34;%s %s %s\u0026#34;, before, mystring, after) } } Ejecución diferida Se puede usar la función defer en funciones para realizar una acción antes de devolver el valor o resolver la funcion, y si se escribe más de una, el orden en ejecución de estas acciones es la contraria, como en learnDefer:\nfunc learnDefer() (ok bool) { // instrucciones diferidas se ejecutan antes de que la función devuelva el resultado. defer fmt.Println (\u0026#34;deferred statements execute in reverse (LIFO) order.\u0026#34;) defer fmt.Println (\u0026#34;\\nThis line is being printed first because\u0026#34;) // defer se utiliza normalmente para cerrar un archivo después de abrirlo. return true } Interfaces Como ejemplo se define una función llamada Stringer que contiene una función llamada String; luego se define una estructura de dos dígitos de tipo int nombrados x y y.\ntype Stringer interface { String() string } type pair struct { x, y int } Aquí se define la función String como un pair, convirtiéndose en un pair para la implementación de la interfaz Stringer. La variable p a continuación se llama receptor (receiver). Observar cómo se accede a los campos de estructura de pair utilizando el nombre de la estructura seguido de un punto y luego el nombre del campo.\nfunc(p pair) String() string { return fmt.Sprintf (\u0026#34;(%d, %d)\u0026#34;, p.x, p.y) } Los puntos y comas se utilizan para crear un elemento de estructura (struct). Se usa la definición corta en el siguiente ejemplo para crear una variable llamada p y especificar su tipo en la estructura de pair.\nfunc learnInterfaces() { p := pair{3, 4} // llamar función String de pair fmt.Println(p.String()) // definir una variable como i del tipo Stringer interface previamente definida var i Stringer // esta igualdad es correcta, porque se aplica pair de Stringer i = p // se llama función String de la variable i de tipo Stringer y se obtiene // el mismo resultado que antes fmt.Println(i.String()) // al pasar las variables anteriores directamente a las funciones de impresión y salida fmt, // estas funciones llaman a la función String para imprimir la representación de la variable. */ // Las siguientes dos líneas dan el mismo resultado de impresión fmt.Println(p) fmt.Println(i) learnVariadicParams (\u0026#34;great\u0026#34;, \u0026#34;learning\u0026#34;, \u0026#34;here!\u0026#34;) } Múltiples entradas Es posible pasar variedad de variables a funciones sin un número definido de parámetros.\nfunc learnVariadicParams (myStrings... interface{}) { // la siguiente iteración recorre los elementos de entrada de datos de la función. for _, param: = range myStrings { fmt.Println(\u0026#34;param:\u0026#34;, param) } // se pasa la entrada de la función variadica como parámetro de otra función (para Sprintln) fmt.Println (\u0026#34;params:\u0026#34;, fmt.Sprintln(myStrings...)) learnErrorHandling() } Manejo de errores La palabra clave \u0026ldquo;ok\u0026rdquo; se utiliza para determinar si una sentencia es correcta. Si ocurre un error, se puede usar una variable err para conocer más detalles sobre el error.\nfunc learnErrorHandling() { m := map [int] string{3: \u0026#34;three\u0026#34;, 4: \u0026#34;four\u0026#34;} if x, ok := m[1]; !ok { // ok aquí será falso porque el número 1 no está en el mapa m fmt.Println(\u0026#34;no one there\u0026#34;) } else { // x será el valor en el mapa fmt.Print(x) } // aqui se intenta convertir valor de texto a número que resultará en un error, // se imprimen los detalles del error si err no es nil */ if _, err := strconv.Atoi(\u0026#34;non-int\u0026#34;); err != nil { fmt.Println(err) } learnConcurrency() } Ejecución simultánea Usando una función anterior para hacer una suma numérica a algunos números en conjunto. Se usa make para crear una variable sin especificar un valor para ella.\nfunc learnConcurrency() { // se crea una variable de tipo canal llamada c c := make(chan int) // creando tres funciones Go concurrentes. Los números se incrementarán simultáneamente // (en paralelo si el dispositivo está configurado para hacerlo). // todas las transmisiones irán al mismo canal // \u0026#34;go\u0026#34; aquí significa iniciar una nueva función go inc(0, c) go inc(10, c) go inc(-805, c) // luego hacer tres lecturas desde el mismo canal e imprimir los resultados. // no hay un orden de acceso de lectura desde el canal, y // también cuando el canal aparece a la derecha de la operación // \u0026lt;- significa que esta leyendo y recibiendo del canal fmt.Println(\u0026lt;-c, \u0026lt;-c, \u0026lt;-c) // nuevo canal con texto cs := make(chan string) // canal contiene canales de texto ccs := make(chan chan string) // enviar valor 84 al canal c go func() {c \u0026lt;- 84}() // enviar palabra al canal cs go func() {cs \u0026lt;- \u0026#34;wordy\u0026#34;}() // instrucción select es similar a la instrucción switch, // pero en cada caso contiene un proceso para un canal que // está listo para comunicarse. select { // valor recibido del canal se puede guardar en una variable case i := \u0026lt;-c: fmt.Printf(\u0026#34;it\u0026#39;s a %T\u0026#34;, i) case \u0026lt;-cs: fmt.Println(\u0026#34;it\u0026#39;s a string\u0026#34;) // canal vacío pero listo para comunicarse case \u0026lt;-ccs: fmt.Println(\u0026#34;didn\u0026#39;t happen.\u0026#34;) } } "},{"href":"https://gophers-latam.github.io/opensource/","title":"Open Source","body":"Software Open Source compartido en GitHub por Gophers LATAM.\n"},{"href":"https://gophers-latam.github.io/contacto/","title":"Contacto","body":"Medios de contacto con Gophers LATAM.\n"},{"href":"https://gophers-latam.github.io/colaboradores/","title":"Colaboradores","body":"Miembros públicos en github.com/gophers-latam\n"},{"href":"https://gophers-latam.github.io/biografia/","title":"Biografía","body":"Gophers LATAM es un esfuerzo conjunto por hacer una comunidad de programadores Golang en Español-Latino.\nLos inicios son desde el canal de YouTube de Tomás Lingotti, luego se adopto la idea del Discord el cual ha sido impulsado desde el mismo canal y en otros canales de YouTube, tales como el de Golandia. Compartido en otros medios como Facebook, Twitter y Linkedin. Y con apoyo desde los inicios de zeroidentidad.\nOtra forma en la que se ha adoptado hacer presencia es en Github.\n\u0026ndash; Todo lo mencionado surgió desde octubre del 2020.\n"},{"href":"https://gophers-latam.github.io/proyectos/awesomelatam/","title":"Awesome Latam","body":"Colección de contenidos y recursos principalmente en Español para desarrolladores de Golang\n"},{"href":"https://gophers-latam.github.io/proyectos/go-tour/","title":"Go Tour","body":"Para aquellos que aún no lo conocen, el \u0026lsquo;Tour de Go\u0026rsquo; representa una introducción excepcional al lenguaje de programación Go. Ofrece ejemplos interactivos y explicaciones detalladas, convirtiéndose en una herramienta invaluable para aquellos que desean aprender Go.\nComo comunidad, hemos realizado la traducción del sitio, permitiendo que cualquier persona de habla hispana tenga acceso a esta valiosa herramienta de aprendizaje.\nEstatus: Pendiente de aprobación por el sitio oficial de Go (https://go-review.googlesource.com/c/website/+/545855).\n"},{"href":"https://gophers-latam.github.io/proyectos/gokey/","title":"GoKey","body":"GoKey es un cache en memoria. El principal aspecto es guardar, leer y borrar entradas dentro del ciclo de vida de la goroutine main. Es decir, si deja de correr, los datos se pierden.\nEstatus: ETAPA 1 - libreria cliente\n"},{"href":"https://gophers-latam.github.io/proyectos/gopherbot/","title":"Gopher-Bot","body":"Bot de discord como mascota y utilidad de comandos en server discord.me/gophers-latam.\nEl bot se encuentra inactivo debido a que kintohub ya dejo de dar servicio. "}]}
\ No newline at end of file