Tutorial de Golang

ยฟQuรฉ es ir?

Go (tambiรฉn conocido como Golang) es un lenguaje de programaciรณn de cรณdigo abierto desarrollado por Google. Es un lenguaje compilado de tipado estรกtico. Go admite programaciรณn concurrente, es decir, permite ejecutar mรบltiples procesos simultรกneamente. Esto se logra mediante canales, goroutines, etc. El lenguaje Go tiene recolecciรณn de basura que se encarga de la gestiรณn de memoria y permite la ejecuciรณn diferida de funciones.

Aprenderemos todos los conceptos bรกsicos de Golang en este tutorial de Learn Go Language.

Cรณmo descargar e instalar GO

Paso 1) Vaya a https://golang.org/dl/. Descarga el binario para tu sistema operativo.

Paso 2) Double Haga clic en el instalador y haga clic en Ejecutar.

Paso 3) Haga clic en Siguiente

Paso 4) Seleccione la carpeta de instalaciรณn y haga clic en Siguiente.

Paso 5) Haga clic en Finalizar una vez que se complete la instalaciรณn.

Paso 6) Una vez completada la instalaciรณn podrรกs verificarla abriendo el terminal y escribiendo

go version

Esto mostrarรก la versiรณn de go instalada.

Su programa First Go: ยกGo Hello World!

Crea una carpeta llamada StudyGo. En este tutorial de lenguaje Go, crearemos nuestros programas Go dentro de esta carpeta. Los archivos Go se crean con la extensiรณn .ir. Puede ejecutar programas Go usando la sintaxis

go run <filename>

Cree un archivo llamado first.go, agregue el siguiente cรณdigo y guรกrdelo.

package main
import ("fmt")

func main() {
	fmt.Println("Hello World! This is my first Go program\n")
}

Navegue a esta carpeta en su terminal. Ejecute el programa usando el comando

Ve a correr primero.

Puedes ver la impresiรณn de salida.

Hello World! This is my first Go program

Ahora analicemos el programa anterior.

paquete principal: cada programa de Go Language debe comenzar con un nombre de paquete. Go nos permite usar paquetes en otros programas de Go y, por lo tanto, admite la reutilizaciรณn del cรณdigo. La ejecuciรณn de un programa Go comienza con el cรณdigo dentro del paquete llamado main.

import fmt: importa el paquete fmt. Este paquete implementa las funciones de E/S.

func main(): esta es la funciรณn desde la cual comienza la ejecuciรณn del programa. La funciรณn principal siempre debe colocarse en el paquete principal. En main(), puedes escribir el cรณdigo dentro de {}.

fmt.Println: esto imprimirรก el texto en la pantalla mediante la funciรณn Println de fmt.

Nota: En las secciones siguientes de este tutorial de Go, cuando mencionas ejecutar/ejecutar el cรณdigo, significa guardar el cรณdigo en un archivo con extensiรณn .go y ejecutarlo usando la sintaxis.

    go run <filename>

Tipos de datos

Los tipos (tipos de datos) representan el tipo de valor almacenado en una variable, el tipo de valor que devuelve una funciรณn, etc.

Hay tres tipos bรกsicos en Go Language

Tipos numรฉricos โ€“ Representan valores numรฉricos que incluyen valores enteros, de punto flotante y complejos. Los distintos tipos numรฉricos son:

int8: enteros de 8 bits con signo.

int16: enteros de 16 bits con signo.

int32: enteros de 32 bits con signo.

int64: enteros de 64 bits con signo.

uint8: enteros sin signo de 8 bits.

uint16: enteros sin signo de 16 bits.

uint32: enteros sin signo de 32 bits.

uint64: enteros sin signo de 64 bits.

float32: nรบmeros de coma flotante de 32 bits.

float64: nรบmeros de coma flotante de 64 bits.

complex64 โ€“ tiene partes reales e imaginarias float32.

complex128 โ€“ tiene partes reales e imaginarias float32.

Tipos de cuerdas โ€“ Representa una secuencia de bytes (caracteres). Se pueden realizar varias operaciones con cadenas, como concatenaciรณn de cadenas, extracciรณn de subcadenas, etc.

Tipos booleanos โ€“ Representa 2 valores, verdadero o falso.

Interfaz de Golang

Interfaz de Golang es una colecciรณn de firmas de mรฉtodos utilizadas por un tipo para implementar el comportamiento de los objetos. El objetivo principal de la interfaz Golang es proporcionar firmas de mรฉtodos con nombres, argumentos y tipos de retorno. Depende de un tipo declarar e implementar el mรฉtodo. Se puede declarar una interfaz en Golang utilizando la palabra clave "interfaz".

Variables

Las variables apuntan a una ubicaciรณn de memoria que almacena algรบn tipo de valor. El parรกmetro de tipo (en la sintaxis siguiente) representa el tipo de valor que se puede almacenar en la ubicaciรณn de la memoria.

La variable se puede declarar usando la sintaxis

    var <variable_name> <type>

Una vez que declara una variable de un tipo, puede asignar la variable a cualquier valor de ese tipo.

Tambiรฉn puede dar un valor inicial a una variable durante la declaraciรณn misma usando

    var <variable_name> <type> = <value>

Si declara la variable con un valor inicial, vaya e infiera el tipo de variable a partir del tipo de valor asignado. Entonces puedes omitir el tipo durante la declaraciรณn usando la sintaxis

    var <variable_name> = <value>

Ademรกs, puedes declarar mรบltiples variables con la sintaxis

    var <variable_name1>, <variable_name2>  = <value1>, <value2>

El siguiente programa en este tutorial de Go tiene algunos ejemplos de declaraciones de variables en Golang.

 
package main
import "fmt"

func main() {
    //declaring a integer variable x
    var x int
    x=3 //assigning x the value 3 
    fmt.Println("x:", x) //prints 3
    
    //declaring a integer variable y with value 20 in a single statement and prints it
    var y int=20
    fmt.Println("y:", y)
    
    //declaring a variable z with value 50 and prints it
    //Here type int is not explicitly mentioned 
    var z=50
    fmt.Println("z:", z)
    
    //Multiple variables are assigned in single line- i with an integer and j with a string
    var i, j = 100,"hello"
    fmt.Println("i and j:", i,j)
}

La salida serรก

x: 3
y: 20
z: 50
i and j: 100 hello

Go Language tambiรฉn proporciona una manera fรกcil de declarar las variables con valor omitiendo la palabra clave var usando

    <variable_name> := <value>

Tenga en cuenta que utilizรณ := en lugar de =. No puedes usar := solo para asignar un valor a una variable que ya estรก declarada. := se utiliza para declarar y asignar valor.

Crea un archivo llamado allow.go con el siguiente cรณdigo

package main
import ("fmt")

func main() {
	a := 20
	fmt.Println(a)

	//gives error since a is already declared
	a := 30
	fmt.Println(a)
}

Ejecute go run asignar.go para ver el resultado como

./assign.go:7:4: no new variables on left side of :=		

Las variables declaradas sin un valor inicial tendrรกn 0 para tipos numรฉricos, falso para booleanos y cadena vacรญa para cadenas.

Constantes

Las variables constantes son aquellas variables cuyo valor no se puede cambiar una vez asignado. Una constante en el lenguaje de programaciรณn Go se declara utilizando la palabra clave "const"

Crea un archivo llamado constant.go y con el siguiente cรณdigo

package main
import ("fmt")

func main() {
	const b =10
	fmt.Println(b)
	b = 30
	fmt.Println(b)
}

Ejecute go run constante.go para ver el resultado como

.constant.go:7:4: cannot assign to b

Para ejemplos de bucles

Los bucles se utilizan para ejecutar un bloque de declaraciones repetidamente segรบn una condiciรณn. La mayorรญa de los lenguajes de programaciรณn proporcionan 3 tipos de bucles: for, while y do while. Pero el lenguaje de programaciรณn Go solo admite bucles.

La sintaxis de un bucle for de Golang es

for initialisation_expression; evaluation_expression; iteration_expression{
   // one or more statement
}

La expresiรณn_inicializaciรณn se ejecuta primero (y solo una vez) en el bucle for de Golang.

Luego se evalรบa la expresiรณn_evaluaciรณn y, si es verdadera, se ejecuta el cรณdigo dentro del bloque.

Se ejecuta el ID de iteration_expression y se vuelve a evaluar la expresiรณn_evaluaciรณn. Si es cierto, el bloque de instrucciones se ejecuta nuevamente. Esto continuarรก hasta que la expresiรณn_evaluaciรณn se vuelva falsa.

Copie el siguiente programa en un archivo y ejecรบtelo para ver Golang for loop imprimiendo nรบmeros del 1 al 5

package main
import "fmt"

func main() {  
var i int
for i = 1; i <= 5; i++ {
fmt.Println(i)
    }
}

La salida es

1
2
3
4
5

Si mas

Si no, es una declaraciรณn condicional. La sinaxis es

if condition{
// statements_1
}else{
// statements_2
}

Aquรญ se evalรบa la condiciรณn y, si es verdadera, se ejecutarรกn las declaraciones_1; de lo contrario, se ejecutarรก la declaraciรณn_2.

Tambiรฉn puedes usar la declaraciรณn if sin mรกs. Tambiรฉn puede tener declaraciones if else encadenadas. Los siguientes programas explicarรกn mรกs sobre if else.

Ejecute el siguiente programa. Comprueba si un nรบmero, x, es menor que 10. Si es asรญ, imprimirรก "x es menor que 10".

package main
import "fmt"

func main() {  
    var x = 50
    if x < 10 {
        //Executes if x < 10
        fmt.Println("x is less than 10")
    } 
}

Aquรญ, dado que el valor de x es mayor que 10, la declaraciรณn dentro de la condiciรณn del bloque if no se ejecutarรก.

Ahora vea el siguiente programa. En este tutorial del lenguaje de programaciรณn Go, tenemos un bloque else que se ejecutarรก si falla la evaluaciรณn if.

package main
import "fmt"

func main() {  
    var x = 50
    if x < 10 {
        //Executes if x is less than 10
        fmt.Println("x is less than 10")
    } else {
        //Executes if x >= 10
        fmt.Println("x is greater than or equals 10")
    }
}

Este programa le darรก resultados.

x is greater than or equals 10

Ahora, en este tutorial de Go, veremos un programa con mรบltiples bloques if else (encadenados if else). Ejecute el siguiente ejemplo de Go. Comprueba si un nรบmero es menor que 10, entre 10 y 90 o mayor que 90.

package main
import "fmt"

func main() {  
    var x = 100
    if x < 10 {
        //Executes if x is less than 10
        fmt.Println("x is less than 10")
    } else if x >= 10 && x <= 90 {
        //Executes if x >= 10 and x<=90
        fmt.Println("x is between 10 and 90")
    } else {
        //Executes if both above cases fail i.e x>90
        fmt.Println("x is greater than 90")
    }
}

Aquรญ primero la condiciรณn if verifica si x es menor que 10 y no lo es. Entonces verifica la siguiente condiciรณn (si no) si estรก entre 10 y 90, lo cual tambiรฉn es falso. Luego ejecuta el bloque en la secciรณn else que proporciona la salida

x is greater than 90

Interruptor

Switch es otra declaraciรณn condicional. Las declaraciones de cambio evalรบan una expresiรณn y el resultado se compara con un conjunto de valores disponibles (casos). Una vez que se encuentra una coincidencia, se ejecutan las declaraciones asociadas con esa coincidencia (caso). Si no se encuentra ninguna coincidencia, no se ejecutarรก nada. Tambiรฉn puede agregar un caso predeterminado para cambiar que se ejecutarรก si no se encuentran otras coincidencias. La sintaxis del interruptor es

switch expression {
    case value_1:
        statements_1
    case value_2:
        statements_2
    case value_n:
        statements_n
    default:
        statements_default
    }

Aquรญ el valor de la expresiรณn se compara con los valores de cada caso. Una vez que se encuentra una coincidencia, se ejecutan las declaraciones asociadas con ese caso. Si no se encuentra ninguna coincidencia, se ejecutan las declaraciones de la secciรณn predeterminada.

Ejecute el siguiente programa

package main
import "fmt"

func main() {  
    a,b := 2,1
    switch a+b {
    case 1:
        fmt.Println("Sum is 1")
    case 2:
        fmt.Println("Sum is 2")
    case 3:
        fmt.Println("Sum is 3")
    default:
        fmt.Println("Printing default")
    }
}

Obtendrรก la salida como

Sum is 3		

Cambie el valor de a y b a 3 y el resultado serรก

Printing default

Tambiรฉn puede tener varios valores en un caso separรกndolos con una coma.

Matrices

La matriz representa una secuencia nombrada de tamaรฑo fijo de elementos del mismo tipo. No puede tener una matriz que contenga nรบmeros enteros y caracteres. No puede cambiar el tamaรฑo de una matriz una vez que define el tamaรฑo.

La sintaxis para declarar una matriz es

var arrayname [size] type

A cada elemento de la matriz se le puede asignar un valor usando la sintaxis

arrayname [index] = value

El รญndice de matriz comienza desde 0 a tamaรฑo-1.

Puede asignar valores a elementos de matriz durante la declaraciรณn usando la sintaxis

arrayname := [size] type {value_0,value_1,โ€ฆ,value_size-1} 

Tambiรฉn puede ignorar el parรกmetro de tamaรฑo al declarar la matriz con valores reemplazando tamaรฑo con ... y el compilador encontrarรก la longitud a partir del nรบmero de valores. La sintaxis es

arrayname :=  [โ€ฆ] type {value_0,value_1,โ€ฆ,value_size-1}

Puede encontrar la longitud de la matriz usando la sintaxis

len(arrayname)

Ejecute el siguiente ejemplo de Go para comprender la matriz

package main
import "fmt"

func main() {  
    var numbers [3] string //Declaring a string array of size 3 and adding elements 
    numbers[0] = "One"
    numbers[1] = "Two"
    numbers[2] = "Three"
    fmt.Println(numbers[1]) //prints Two
    fmt.Println(len(numbers)) //prints 3
    fmt.Println(numbers) // prints [One Two Three]

    directions := [...] int {1,2,3,4,5} // creating an integer array and the size of the array is defined by the number of elements 
    fmt.Println(directions) //prints [1 2 3 4 5]
    fmt.Println(len(directions)) //prints 5

    //Executing the below commented statement prints invalid array index 5 (out of bounds for 5-element array)
    //fmt.Println(directions[5]) 
}

Salida

Two
3
[One Two Three]
[1 2 3 4 5]
5

Funciรณn Golang Slice y Append

Un sector es una porciรณn o segmento de una matriz. O es una vista o vista parcial de una matriz subyacente a la que apunta. Puede acceder a los elementos de un sector utilizando el nombre del sector y el nรบmero de รญndice tal como lo hace en una matriz. No puede cambiar la longitud de una matriz, pero puede cambiar el tamaรฑo de un segmento.

Los contenidos de un segmento son en realidad punteros a los elementos de una matriz. Significa Si cambia cualquier elemento en un segmento, el contenido de la matriz subyacente tambiรฉn se verรก afectado.

La sintaxis para crear un sector es

var slice_name [] type = array_name[start:end]

Esto crearรก un segmento llamado nombre_sector a partir de una matriz llamada nombre_matriz con los elementos en el รญndice de principio a fin-1.

Ahora, en este tutorial de Golang, ejecutaremos el siguiente programa. El programa crearรก una porciรณn de la matriz y la imprimirรก. Ademรกs, puede ver que modificar el contenido del segmento modificarรก la matriz real.

package main
import "fmt"

func main() {  
    // declaring array
    a := [5] string {"one", "two", "three", "four", "five"}
    fmt.Println("Array after creation:",a)

    var b [] string = a[1:4] //created a slice named b
    fmt.Println("Slice after creation:",b)

    b[0]="changed" // changed the slice data
    fmt.Println("Slice after modifying:",b)
    fmt.Println("Array after slice modification:",a)
}

Esto imprimirรก el resultado como

Array after creation: [one two three four five]
Slice after creation: [two three four]
Slice after modifying: [changed three four]
Array after slice modification: [one changed three four five]

Hay ciertas funciones como Golang len, Golang append que puedes aplicar en sectores

len(nombre_porciรณn) โ€“ devuelve la longitud del segmento

agregar(nombre_porciรณn, valor_1, valor_2) โ€“ Golang append se utiliza para agregar valor_1 y valor_2 a un segmento existente.

agregar(slice_nale1,slice_name2โ€ฆ) โ€“ aรฑade nombre_porciรณn2 a nombre_porciรณn1

Ejecute el siguiente programa.

package main
import "fmt"

func main() {  
	a := [5] string {"1","2","3","4","5"}
	slice_a := a[1:3]
	b := [5] string {"one","two","three","four","five"}
	slice_b := b[1:3]

    fmt.Println("Slice_a:", slice_a)
    fmt.Println("Slice_b:", slice_b)
    fmt.Println("Length of slice_a:", len(slice_a))
    fmt.Println("Length of slice_b:", len(slice_b))

    slice_a = append(slice_a,slice_b...) // appending slice
    fmt.Println("New Slice_a after appending slice_b :", slice_a)
    
    slice_a = append(slice_a,"text1") // appending value
    fmt.Println("New Slice_a after appending text1 :", slice_a)
}

La salida serรก

Slice_a: [2 3]
Slice_b: [two three]
Length of slice_a: 2
Length of slice_b: 2
New Slice_a after appending slice_b : [2 3 two three]
New Slice_a after appending text1 : [2 3 two three text1]

El programa primero crea 2 cortes e imprime su longitud. Luego agregรณ un segmento a otro y luego agregรณ una cadena al segmento resultante.

Funciones

Una funciรณn representa un bloque de declaraciones que realiza una tarea especรญfica. Una declaraciรณn de funciรณn nos dice el nombre de la funciรณn, el tipo de retorno y los parรกmetros de entrada. La definiciรณn de funciรณn representa el cรณdigo contenido en la funciรณn. La sintaxis para declarar la funciรณn es

func function_name(parameter_1 type, parameter_n type) return_type {
//statements
}

Los parรกmetros y tipos de retorno son opcionales. Ademรกs, puede devolver varios valores de una funciรณn.

Ahora, en este tutorial de Golang, ejecutemos el siguiente ejemplo de Golang. Aquรญ, la funciรณn denominada calc aceptarรก dos nรบmeros y realizarรก la suma y la resta y devolverรก ambos valores.

package main
import "fmt"

//calc is the function name which accepts two integers num1 and num2
//(int, int) says that the function returns two values, both of integer type.
func calc(num1 int, num2 int)(int, int) {  
    sum := num1 + num2
    diff := num1 - num2
    return sum, diff
}

func main() {  
    x,y := 15,10

    //calls the function calc with x and y an d gets sum, diff as output
    sum, diff := calc(x,y) 
    fmt.Println("Sum",sum)
    fmt.Println("Diff",diff) 
}

La salida serรก

Sum 25
Diff 5

Paquetes

Los paquetes se utilizan para organizar el cรณdigo. En un proyecto grande, no es factible escribir cรณdigo en un solo archivo. El lenguaje de programaciรณn Go nos permite organizar el cรณdigo en diferentes paquetes. Esto aumenta la legibilidad y reutilizaciรณn del cรณdigo. Un programa Go ejecutable debe contener un paquete llamado main y la ejecuciรณn del programa comienza desde la funciรณn llamada main. Puede importar otros paquetes en nuestro programa usando la sintaxis

import package_name

Veremos y discutiremos en este tutorial de Golang, cรณmo crear y usar paquetes en el siguiente ejemplo de Golang.

Paso 1) Cree un archivo llamado package_example.go y agregue el siguiente cรณdigo

package main
import "fmt"
//the package to be created
import "calculation"

func main() {  
	x,y := 15,10
	//the package will have function Do_add()
sum := calculation.Do_add(x,y)
fmt.Println("Sum",sum) 
}

En el programa anterior, fmt es un paquete que el lenguaje de programaciรณn Go nos proporciona principalmente para fines de E/S. Ademรกs, puede ver un paquete llamado cรกlculo. Dentro de main() puedes ver una suma de pasos: = cรกlculo.Do_add(x,y). Significa que estรกs invocando la funciรณn Do_add desde el cรกlculo del paquete.

Paso 2) Primero, debe crear el cรกlculo del paquete dentro de una carpeta con el mismo nombre en la carpeta src de go. La ruta instalada de go se puede encontrar en la variable PATH.

Para mac, busque la ruta ejecutando echo $PATH

Entonces la ruta es /usr/local/go

Para Windows, busque la ruta ejecutando echo %GOROOT%

Aquรญ la ruta es C:\Go\

Paso 3) Vaya a la carpeta src (/usr/local/go/src para Mac y C:\Go\src para Windows). Ahora, segรบn el cรณdigo, el nombre del paquete es cรกlculo. Go requiere que el paquete se coloque en un directorio con el mismo nombre dentro del directorio src. Cree un directorio llamado cรกlculo en la carpeta src.

Paso 4) Cree un archivo llamado calc.go (puede darle cualquier nombre, pero el nombre del paquete en el cรณdigo importa. Aquรญ deberรญa estar el cรกlculo) dentro del directorio de cรกlculo y agregue el siguiente cรณdigo

package calculation
  
func Do_add(num1 int, num2 int)(int) {
    sum := num1 + num2
    return sum
}

Paso 5) Ejecute el comando go install desde el directorio de cรกlculo que compilarรก calc.go.

Paso 6) Ahora regrese a package_example.go y ejecute go run package_example.go. La salida serรก Sum 25.

Tenga en cuenta que el nombre de la funciรณn Do_add comienza con una letra mayรบscula. Esto se debe a que en Go, si el nombre de la funciรณn comienza con una letra mayรบscula, significa que otros programas pueden verla (acceder), de lo contrario, otros programas no pueden acceder a ella. Si el nombre de la funciรณn fuera do_add, entonces habrรญa recibido el error

no se puede hacer referencia al nombre no exportado cรกlculo.calc.

Aplazar y apilar aplazamientos

Las declaraciones diferidas se utilizan para diferir la ejecuciรณn de una llamada a funciรณn hasta que la funciรณn que contiene la declaraciรณn diferida complete su ejecuciรณn.

Aprendamos esto con un ejemplo:

package main
import "fmt"

func sample() {  
    fmt.Println("Inside the sample()")
}
func main() {  
    //sample() will be invoked only after executing the statements of main()
    defer sample()
    fmt.Println("Inside the main()")
}

La salida serรก

Inside the main()
Inside the sample()

Aquรญ la ejecuciรณn de sample() se difiere hasta que se completa la ejecuciรณn de la funciรณn adjunta (main()).

Apilar aplazar consiste en utilizar mรบltiples declaraciones de aplazar. Suponga que tiene varias declaraciones diferidas dentro de una funciรณn. Go coloca todas las llamadas a funciones diferidas en una pila y, una vez que regresa la funciรณn adjunta, las funciones apiladas se ejecutan en el Orden รบltimo en entrar, primero en salir (LIFO). Puedes ver esto en el siguiente ejemplo.

Ejecute el siguiente cรณdigo

package main
import "fmt"

func display(a int) {  
    fmt.Println(a)
}
func main() {  
    defer display(1)
    defer display(2)
    defer display(3)
    fmt.Println(4)
}

La salida serรก

4
3
2
1			

Aquรญ el cรณdigo dentro de main() se ejecuta primero, y luego las llamadas a funciones diferidas se ejecutan en orden inverso, es decir, 4, 3,2,1.

Punteros

Antes de explicar los punteros, analicemos primero el operador "&". El operador "&" se utiliza para obtener la direcciรณn de una variable. Esto significa que "&a" imprimirรก la direcciรณn de memoria de la variable a.

En este tutorial de Golang, ejecutaremos el siguiente programa para mostrar el valor de una variable y la direcciรณn de esa variable.

package main
import "fmt"

func main() {
	a := 20
	fmt.Println("Address:",&a)
	fmt.Println("Value:",a)
}

El resultado serรก

Address: 0xc000078008
Value: 20

Una variable de puntero almacena la direcciรณn de memoria de otra variable. Puede definir un puntero usando la sintaxis

	var variable_name *type

El asterisco (*) representa que la variable es un puntero. Comprenderรก mรกs ejecutando el siguiente programa.

package main
import "fmt"

func main() {
	//Create an integer variable a with value 20
	a := 20
	
	//Create a pointer variable b and assigned the address of a
	var b *int = &a

	//print address of a(&a) and value of a  
	fmt.Println("Address of a:",&a)
	fmt.Println("Value of a:",a)

	//print b which contains the memory address of a i.e. &a
	fmt.Println("Address of pointer b:",b)

	//*b prints the value in memory address which b contains i.e. the value of a
	fmt.Println("Value of pointer b",*b)

	//increment the value of variable a using the variable b
	*b = *b+1

	//prints the new value using a and *b
	fmt.Println("Value of pointer b",*b)
	fmt.Println("Value of a:",a)}

La salida serรก

Address of a: 0x416020
Value of a: 20
Address of pointer b: 0x416020
Value of pointer b 20
Value of pointer b 21
Value of a: 21

Estructuras

Una estructura es un tipo de datos definido por el usuario que a su vez contiene un elemento mรกs del mismo o diferente tipo.

Usar una estructura es un proceso de 2 pasos.

Primero, cree (declare) un tipo de estructura.

En segundo lugar, cree variables de ese tipo para almacenar valores.

Las estructuras se utilizan principalmente cuando se desea almacenar datos relacionados juntos.

Considere una informaciรณn del empleado que tenga nombre, edad y direcciรณn. Puedes manejar esto de 2 maneras.

Cree 3 matrices: una matriz almacena los nombres de los empleados, otra almacena la edad y la tercera almacena la edad.

Declare un tipo de estructura con 3 campos: nombre, direcciรณn y edad. Cree una matriz de ese tipo de estructura donde cada elemento sea un objeto de estructura que tenga nombre, direcciรณn y edad.

El primer enfoque no es eficiente. En este tipo de escenarios, las estructuras son mรกs convenientes.

La sintaxis para declarar una estructura es

type structname struct {
   variable_1 variable_1_type
   variable_2 variable_2_type
   variable_n variable_n_type
}

Un ejemplo de declaraciรณn de estructura es

type emp struct {
    name string
    address string
    age int
}

Aquรญ se crea un nuevo tipo definido por el usuario llamado emp. Ahora puedes crear variables del tipo emp usando la sintaxis

	var variable_name struct_name

Un ejemplo es

var empdata1 emp 

Puede establecer valores para empdata1 como

empdata1.name = "John"
	empdata1.address = "Street-1, Bangalore"
	empdata1.age = 30

Tambiรฉn puede crear una variable de estructura y asignar valores mediante

empdata2 := emp{"Raj", "Building-1, Delhi", 25}

Aquรญ es necesario mantener el orden de los elementos. Raj se asignarรก al nombre, el siguiente elemento a la direcciรณn y el รบltimo a la edad.

Ejecute el siguiente cรณdigo

package main
import "fmt"

//declared the structure named emp
type emp struct {
        name string
        address string
        age int
}       

//function which accepts variable of emp type and prints name property
func display(e emp) {
          fmt.Println(e.name)
}

func main() {
// declares a variable, empdata1, of the type emp
var empdata1 emp
//assign values to members of empdata1
empdata1.name = "John"
empdata1.address = "Street-1, London"
empdata1.age = 30

//declares and assign values to variable empdata2 of type emp
empdata2 := emp{"Raj", "Building-1, Paris", 25}

//prints the member name of empdata1 and empdata2 using display function
display(empdata1)
display(empdata2)
}

Salida

John
Raj

Mรฉtodos (no funciones)

Un mรฉtodo es una funciรณn con un argumento receptor. ArchiTรฉcnicamente, estรก entre la palabra clave func y el nombre del mรฉtodo. La sintaxis de un mรฉtodo es

func (variable variabletype) methodName(parameter1 paramether1type) {  
}

Convirtamos el programa de ejemplo anterior para usar mรฉtodos en lugar de funciones.

package main
import "fmt"

//declared the structure named emp
type emp struct {
    name string
    address string
    age int
}

//Declaring a function with receiver of the type emp
func(e emp) display() {
    fmt.Println(e.name)
}

func main() {
    //declaring a variable of type emp
    var empdata1 emp
    
    //Assign values to members
    empdata1.name = "John"
    empdata1.address = "Street-1, Lodon"
    empdata1.age = 30

    //declaring a variable of type emp and assign values to members
    empdata2 := emp {
        "Raj", "Building-1, Paris", 25}

    //Invoking the method using the receiver of the type emp
   // syntax is variable.methodname()
    empdata1.display()
    empdata2.display()
}

Go no es un lenguaje orientado a objetos y no tiene el concepto de clase. Los mรฉtodos dan una idea de lo que se hace en los programas orientados a objetos donde las funciones de una clase se invocan usando la sintaxis nombreobjeto.nombrefunciรณn()

Concurrencia

Go admite la ejecuciรณn simultรกnea de tareas, es decir, puede ejecutar varias tareas simultรกneamente. Es diferente del concepto de paralelismo. En el paralelismo, una tarea se divide en pequeรฑas subtareas y se ejecutan en paralelo, pero en la concurrencia, se ejecutan varias tareas simultรกneamente. La concurrencia se logra en Go mediante Goroutines y Canales.

gorutinas

Una gorutina es una funciรณn que puede ejecutarse simultรกneamente con otras funciones. Por lo general, cuando se invoca una funciรณn, el control se transfiere a la funciรณn llamada y, una vez completada la ejecuciรณn, el control regresa a la funciรณn que llama. La funciรณn que llama luego continรบa su ejecuciรณn. La funciรณn que llama espera a que la funciรณn invocada complete la ejecuciรณn antes de continuar con el resto de las declaraciones.

Pero en el caso de goroutine, la funciรณn que llama no esperarรก a que se complete la ejecuciรณn de la funciรณn invocada. Continuarรก ejecutรกndose con las siguientes declaraciones. Puede tener varias gorutinas en un programa.

Ademรกs, el programa principal saldrรก una vez que complete la ejecuciรณn de sus declaraciones y no esperarรก a que se completen las rutinas invocadas.

Goroutine se invoca utilizando la palabra clave go seguida de una llamada a funciรณn.

Ejemplo

go add(x,y)

Comprenderรก las gorutinas con los siguientes ejemplos de Golang. Ejecute el siguiente programa

package main
import "fmt"
    
func display() {
	for i:=0; i<5; i++ {
		fmt.Println("In display")
	}
}

func main() {
	//invoking the goroutine display()
	go display()
	//The main() continues without waiting for display()
	for i:=0; i<5; i++ {
		fmt.Println("In main")
	}
}

La salida serรก

In main
In main
In main
In main
In main

Aquรญ el programa principal completรณ la ejecuciรณn incluso antes de que comenzara la rutina. display() es una rutina que se invoca usando la sintaxis

go function_name(parameter list)

En el cรณdigo anterior, main() no espera a que se complete display(), y main() completรณ su ejecuciรณn antes de que display() ejecutara su cรณdigo. Entonces la declaraciรณn de impresiรณn dentro de display() no se imprimiรณ.

Ahora modificamos el programa para imprimir tambiรฉn las declaraciones desde display(). Agregamos un retraso de 2 segundos en el bucle for de main() y un retraso de 1 segundo en el bucle for de display().

package main
import "fmt"
import "time"
    
func display() {
	for i:=0; i<5; i++ {
		time.Sleep(1 * time.Second)
		fmt.Println("In display")
	}
}

func main() {
	//invoking the goroutine display()
	go display()
	for i:=0; i<5; i++ {
		time.Sleep(2 * time.Second)
		fmt.Println("In main")
	}
}

La salida serรก algo similar a

In display
In main
In display
In display
In main
In display
In display
In main
In main
In main

Aquรญ puede ver que ambos bucles se ejecutan de forma superpuesta debido a la ejecuciรณn simultรกnea.

Canales

Los canales son una forma para que las funciones se comuniquen entre sรญ. Se puede pensar como un medio donde una rutina coloca los datos y otra rutina accede a ellos en el servidor Golang.

Un canal se puede declarar con la sintaxis

channel_variable := make(chan datatype)

Ejemplo:

	ch := make(chan int)

Puedes enviar datos a un canal usando la sintaxis

channel_variable <- variable_name

Ejemplo

    ch <- x

Puede recibir datos de un canal usando la sintaxis

    variable_name := <- channel_variable

Ejemplo

   y := <- ch

En los ejemplos de goroutine del lenguaje Go anteriores, ha visto que el programa principal no espera a la goroutine. Pero ese no es el caso cuando se trata de canales. Supongamos que si una gorutina envรญa datos al canal, main() esperarรก la declaraciรณn que recibe los datos del canal hasta que obtenga los datos.

Verรก esto en los siguientes ejemplos de lenguaje Go. Primero, escriba una rutina normal y observe el comportamiento. Luego modifique el programa para usar canales y vea el comportamiento.

Ejecute el siguiente programa

package main
import "fmt"
import "time"
    
func display() {
	time.Sleep(5 * time.Second)
	fmt.Println("Inside display()")
}

func main() {
	go display()
	fmt.Println("Inside main()")
}

La salida serรก

Inside main()

main() finalizรณ la ejecuciรณn y saliรณ antes de que se ejecutara la rutina. Entonces la impresiรณn dentro de display() no se ejecutรณ.

Ahora modifique el programa anterior para usar canales y ver el comportamiento.

package main
import "fmt"
import "time"
    
func display(ch chan int) {
	time.Sleep(5 * time.Second)
	fmt.Println("Inside display()")
	ch <- 1234
}

func main() {
	ch := make(chan int) 
	go display(ch)
	x := <-ch
	fmt.Println("Inside main()")
	fmt.Println("Printing x in main() after taking from channel:",x)
}

La salida serรก

Inside display()
Inside main()
Printing x in main() after taking from channel: 1234

Aquรญ lo que sucede es que main() al llegar a x := <-ch esperarรก datos en el canal ch. El display() tiene una espera de 5 segundos y luego envรญa datos al canal ch. El main() al recibir los datos del canal se desbloquea y continรบa su ejecuciรณn.

El remitente que envรญa datos al canal puede informar a los receptores que no se agregarรกn mรกs datos al canal al cerrarlo. Esto se utiliza principalmente cuando se utiliza un bucle para enviar datos a un canal. Un canal se puede cerrar usando

close(channel_name)

Y en el extremo del receptor, es posible verificar si el canal estรก cerrado usando una variable adicional mientras se obtienen datos del canal usando

variable_name, status := <- channel_variable

Si el estado es Verdadero, significa que recibiรณ datos del canal. Si es falso, significa que estรกs intentando leer desde un canal cerrado.

Tambiรฉn puede utilizar canales para la comunicaciรณn entre gorutinas. Es necesario utilizar 2 gorutinas: una envรญa datos al canal y la otra recibe los datos del canal. Vea el programa a continuaciรณn

package main
import "fmt"
import "time"

//This subroutine pushes numbers 0 to 9 to the channel and closes the channel
func add_to_channel(ch chan int) {	
	fmt.Println("Send data")
	for i:=0; i<10; i++ {
		ch <- i //pushing data to channel
	}
	close(ch) //closing the channel

}

//This subroutine fetches data from the channel and prints it.
func fetch_from_channel(ch chan int) {
	fmt.Println("Read data")
	for {
		//fetch data from channel
x, flag := <- ch

		//flag is true if data is received from the channel
//flag is false when the channel is closed
if flag == true {
			fmt.Println(x)
		}else{
			fmt.Println("Empty channel")
			break	
		}	
	}
}

func main() {
	//creating a channel variable to transport integer values
	ch := make(chan int)

	//invoking the subroutines to add and fetch from the channel
	//These routines execute simultaneously
	go add_to_channel(ch)
	go fetch_from_channel(ch)

	//delay is to prevent the exiting of main() before goroutines finish
	time.Sleep(5 * time.Second)
	fmt.Println("Inside main()")
}

Aquรญ hay 2 subrutinas, una envรญa datos al canal y la otra los imprime. La funciรณn add_to_channel suma los nรบmeros del 0 al 9 y cierra el canal. Simultรกneamente, la funciรณn fetch_from_channel espera

x, flag := <- ch y una vez que los datos estรฉn disponibles, los imprime. Sale una vez que la bandera es falsa, lo que significa que el canal estรก cerrado.

La espera en main() se da para evitar la salida de main() hasta que las gorutinas finalicen la ejecuciรณn.

Ejecute el cรณdigo y vea el resultado como

Read data
Send data
0
1
2
3
4
5
6
7
8
9
Empty channel
Inside main()

Seleccione

Seleccionar puede verse como una declaraciรณn de cambio que funciona en canales. Aquรญ las declaraciones del caso serรกn una operaciรณn de canal. Por lo general, las declaraciones de cada caso se leerรกn desde el canal. Cuando cualquiera de los casos estรก listo (se lee el canal), se ejecuta la declaraciรณn asociada con ese caso. Si hay varios casos listos, elegirรก uno al azar. Puede tener un caso predeterminado que se ejecute si ninguno de los casos estรก listo.

Veamos el siguiente cรณdigo.

package main
import "fmt"
import "time"

//push data to channel with a 4 second delay
func data1(ch chan string) {  
    time.Sleep(4 * time.Second)
    ch <- "from data1()"
}

//push data to channel with a 2 second delay
func data2(ch chan string) {  
    time.Sleep(2 * time.Second)
    ch <- "from data2()"
}

func main() {
    //creating channel variables for transporting string values
    chan1 := make(chan string)
    chan2 := make(chan string)
    
    //invoking the subroutines with channel variables
    go data1(chan1)
    go data2(chan2)
    
    //Both case statements wait for data in the chan1 or chan2.
    //chan2 gets data first since the delay is only 2 sec in data2().
    //So the second case will execute and exits the select block
    select {
    case x := <-chan1:
        fmt.Println(x)
    case y := <-chan2:
        fmt.Println(y)
    }
}

La ejecuciรณn del programa anterior darรก el resultado:

from data2()

Aquรญ la declaraciรณn de selecciรณn espera a que los datos estรฉn disponibles en cualquiera de los canales. data2() agrega datos al canal despuรฉs de un perรญodo de suspensiรณn de 2 segundos, lo que harรก que se ejecute el segundo caso.

Agregue un caso predeterminado a la selecciรณn en el mismo programa y vea el resultado. Aquรญ, al llegar al bloque de selecciรณn, si ningรบn caso tiene datos listos en el canal, ejecutarรก el bloque predeterminado sin esperar a que los datos estรฉn disponibles en ningรบn canal.

package main
import "fmt"
import "time"

//push data to channel with a 4 second delay
func data1(ch chan string) {  
    time.Sleep(4 * time.Second)
    ch <- "from data1()"
}

//push data to channel with a 2 second delay
func data2(ch chan string) {  
    time.Sleep(2 * time.Second)
    ch <- "from data2()"
}

func main() {
    //creating channel variables for transporting string values  
    chan1 := make(chan string)
    chan2 := make(chan string)
    
    //invoking the subroutines with channel variables
    go data1(chan1)
    go data2(chan2)

    //Both case statements check for data in chan1 or chan2.
    //But data is not available (both routines have a delay of 2 and 4 sec)
    //So the default block will be executed without waiting for data in channels.
    select {
    case x := <-chan1:
        fmt.Println(x)
    case y := <-chan2:
        fmt.Println(y)
    default:
    	fmt.Println("Default case executed")
    }
}

Este programa darรก el resultado:

Default case executed			

Esto se debe a que cuando llegรณ el bloque de selecciรณn, ningรบn canal tenรญa datos para leer. Entonces, se ejecuta el caso predeterminado.

Mutex

Mutex es la forma abreviada de exclusiรณn mutua. Mutex se utiliza cuando no se desea permitir que varias subrutinas accedan a un recurso al mismo tiempo. Mutex tiene dos mรฉtodos: bloquear y desbloquear. Mutex estรก incluido en el paquete sync, por lo que hay que importar el paquete sync. Las instrucciones que se deben ejecutar de forma mutuamente exclusiva se pueden colocar dentro de mutex.Lock() y mutex.Unlock().

Aprendamos mutex con un ejemplo que cuenta el nรบmero de veces que se ejecuta un bucle. En este programa esperamos que la rutina ejecute el bucle 10 veces y el recuento se almacene en suma. Llamas a esta rutina 3 veces, por lo que el recuento total debe ser 30. El recuento se almacena en una variable global.

Primero, ejecuta el programa sin mutex.

package main
import "fmt"
import "time"
import "strconv"
import "math/rand"
//declare count variable, which is accessed by all the routine instances
var count = 0

//copies count to temp, do some processing(increment) and store back to count
//random delay is added between reading and writing of count variable
func process(n int) {
	//loop incrementing the count by 10
	for i := 0; i < 10; i++ {
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		temp := count
		temp++
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		count = temp
	}
	fmt.Println("Count after i="+strconv.Itoa(n)+" Count:", strconv.Itoa(count))
}

func main() {
	//loop calling the process() 3 times
	for i := 1; i < 4; i++ {
		go process(i)
	}

	//delay to wait for the routines to complete
	time.Sleep(25 * time.Second)
	fmt.Println("Final Count:", count)
}

Ver el resultado

 Count after i=1 Count: 11
Count after i=3 Count: 12
Count after i=2 Count: 13
Final Count: 13

El resultado podrรญa ser diferente cuando lo ejecutes pero el resultado final no serรก 30.

Aquรญ lo que sucede es que 3 gorutinas intentan aumentar el recuento de bucles almacenado en la variable recuento. Supongamos que en un momento el recuento es 5 y goroutine1 va a incrementar el recuento a 6. Los pasos principales incluyen

Copiar recuento a temperatura

Incrementar temperatura

Almacenar la temperatura nuevamente para contar

Supongamos que poco despuรฉs de realizar el paso 3 de goroutine1; otra gorutina podrรญa tener un valor antiguo, digamos que 3 realiza los pasos anteriores y almacena 4 nuevamente, lo cual es incorrecto. Esto se puede evitar usando mutex, que hace que otras rutinas esperen cuando una rutina ya estรก usando la variable.

Ahora ejecutarรก el programa con mutex. Aquรญ los 3 pasos mencionados anteriormente se ejecutan en un mutex.

package main
import "fmt"
import "time"
import "sync"
import "strconv"
import "math/rand"

//declare a mutex instance
var mu sync.Mutex

//declare count variable, which is accessed by all the routine instances
var count = 0

//copies count to temp, do some processing(increment) and store back to count
//random delay is added between reading and writing of count variable
func process(n int) {
	//loop incrementing the count by 10
	for i := 0; i < 10; i++ {
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		//lock starts here
		mu.Lock()
		temp := count
		temp++
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		count = temp
		//lock ends here
		mu.Unlock()
	}
	fmt.Println("Count after i="+strconv.Itoa(n)+" Count:", strconv.Itoa(count))
}

func main() {
	//loop calling the process() 3 times
	for i := 1; i < 4; i++ {
		go process(i)
	}

	//delay to wait for the routines to complete
	time.Sleep(25 * time.Second)
	fmt.Println("Final Count:", count)
}

Ahora la salida serรก

 Count after i=3 Count: 21
Count after i=2 Count: 28
Count after i=1 Count: 30
Final Count: 30

Aquรญ obtenemos el resultado esperado como resultado final. Porque las declaraciones de lectura, incremento y reescritura del recuento se ejecutan en un mutex.

Manejo de errores

Los errores son condiciones anormales como cerrar un archivo que no estรก abierto, abrir un archivo que no existe, etc. Las funciones generalmente devuelven errores como รบltimo valor de retorno.

El siguiente ejemplo explica mรกs sobre el error.

package main
import "fmt"
import "os"

//function accepts a filename and tries to open it.
func fileopen(name string) {
    f, er := os.Open(name)

    //er will be nil if the file exists else it returns an error object  
    if er != nil {
        fmt.Println(er)
        return
    }else{
    	fmt.Println("file opened", f.Name())
    }
}

func main() {  
    fileopen("invalid.txt")
}

La salida serรก:

open /invalid.txt: no such file or directory

Aquรญ intentamos abrir un archivo que no existe y devolviรณ el error a la variable er. Si el archivo es vรกlido, entonces el error serรก nulo.

Errores personalizados

Con esta funciรณn, puede crear errores personalizados. Esto se hace usando New() del paquete de error. Reescribiremos el programa anterior para utilizar errores personalizados.

Ejecute el siguiente programa

package main
import "fmt"
import "os"
import "errors"

//function accepts a filename and tries to open it.
func fileopen(name string) (string, error) {
    f, er := os.Open(name)

    //er will be nil if the file exists else it returns an error object  
    if er != nil {
        //created a new error object and returns it  
        return "", errors.New("Custom error message: File name is wrong")
    }else{
    	return f.Name(),nil
    }
}

func main() {  
    //receives custom error or nil after trying to open the file
    filename, error := fileopen("invalid.txt")
    if error != nil {
        fmt.Println(error)
    }else{
    	fmt.Println("file opened", filename)
    }  
}

La salida serรก:

Custom error message:File name is wrong

Aquรญ el รกrea() devuelve el รกrea de un cuadrado. Si la entrada es menor que 1, entonces area() devuelve un mensaje de error.

Leer archivos

Los archivos se utilizan para almacenar datos. Go nos permite leer datos de los archivos

Primero cree un archivo, data.txt, en su directorio actual con el siguiente contenido.

Line one
Line two
Line three

Ahora ejecute el siguiente programa para ver cรณmo imprime el contenido del archivo completo como salida.

package main
import "fmt"
import "io/ioutil"

func main() {  
    data, err := ioutil.ReadFile("data.txt")
    if err != nil {
        fmt.Println("File reading error", err)
        return
    }
    fmt.Println("Contents of file:", string(data))
}

Aquรญ los datos, err := ioutil.ReadFile(โ€œdata.txtโ€) lee los datos y devuelve una secuencia de bytes. Mientras se imprime, se convierte al formato de cadena.

Escribir archivos

Verรกs esto con un programa.

package main
import "fmt"
import "os"

func main() {  
    f, err := os.Create("file1.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    l, err := f.WriteString("Write Line one")
    if err != nil {
        fmt.Println(err)
        f.Close()
        return
    }
    fmt.Println(l, "bytes written")
    err = f.Close()
    if err != nil {
        fmt.Println(err)
        return
    }
}

Aquรญ se crea un archivo, test.txt. Si el archivo ya existe, su contenido se trunca. Writeline() se utiliza para escribir el contenido del archivo. Despuรฉs de eso, cerrรณ el archivo usando Close().

Hoja de trucos

En este tutorial de Go, cubrimos,

Tema Descripciรณn Sintaxis
Tipos basicos Numรฉrico, cadena, bool
Variables Declarar y asignar valores a variables. var tipo nombre_variable
var nombre_variable tipo = valor
var nombre_variable1, nombre_variable2 = valor1, valor2
nombre_variable := valor
Constantes Variables cuyo valor no se puede cambiar una vez asignado variable constante = valor
En bucle Ejecutar declaraciones en un bucle. para inicializaciรณn_expresiรณn; expresiรณn_evaluaciรณn; iteraciรณn_expresiรณn{
// una o mรกs declaraciones
}
Si mas Es una declaraciรณn condicional. si condiciรณn {
// declaraciones_1
Else {}
// declaraciones_2
}
cambiar Declaraciรณn condicional con mรบltiples casos. cambiar de expresiรณn {
valor de caso_1:
declaraciones_1
valor de caso_2:
declaraciones_2
valor de caso_n:
declaraciones_n
por defecto:
declaraciones_predeterminadas
}
Formaciรณn Secuencia con nombre de tamaรฑo fijo de elementos del mismo tipo nombre de matriz: = [tamaรฑo] escriba {valor_0, valor_1,โ€ฆ, valor_tamaรฑo-1}
Rebanada Porciรณn o segmento de una matriz var nombre_porciรณn [] tipo = nombre_matriz[inicio:fin]
Funciones Bloque de declaraciones que realiza una tarea especรญfica. func nombre_funciรณn (tipo parรกmetro_1, tipo parรกmetro_n) tipo_retorno {
//declaraciones
}
Paquetes Se utilizan para organizar el cรณdigo. Aumenta la legibilidad y reutilizaciรณn del cรณdigo. importar nombre_paquete
Aplazar Difiere la ejecuciรณn de una funciรณn hasta que la funciรณn que la contiene finaliza su ejecuciรณn. diferir nombre_funciรณn(lista_parรกmetros)
Punteros Almacena la direcciรณn de memoria de otra variable. var nombre_variable *tipo
Estructura Tipo de datos definido por el usuario que a su vez contiene un elemento mรกs del mismo o diferente tipo escriba nombre de estructura estructura {
variable_1 variable_1_tipo
variable_2 variable_2_tipo
variable_n variable_n_tipo
}
Mรฉtodos Un mรฉtodo es una funciรณn con un argumento receptor. func (variable tipo de variable) nombre_mรฉtodo(lista_parรกmetros) {
}
gorutina Una funciรณn que puede ejecutarse simultรกneamente con otras funciones. ir nombre_funciรณn(lista_parรกmetros)
Channel Manera de que las funciones se comuniquen entre sรญ. Medio en el que una rutina coloca datos y al que otra rutina accede. Declarar:
ch:= hacer(chan int)
Enviar datos al canal:
variable_canal <- nombre_variable
Recibir del canal:
nombre_variable := <- variable_canal
Seleccione Declaraciรณn de cambio que funciona en canales. Las declaraciones del caso serรกn una operaciรณn de canal. Cuando cualquiera de los canales estรก listo con datos, se ejecuta la declaraciรณn asociada con ese caso. seleccionar {
caso x := <-chan1:
fmt.Println(x)
caso y := <-chan2:
fmt.Println(y)
}
Mutex Mutex se utiliza cuando no se desea permitir que varias subrutinas accedan a un recurso al mismo tiempo. Mutex tiene 2 mรฉtodos: bloquear y desbloquear mutex.Lock()
//declaraciones
mutex.Desbloquear().
Leer archivos Lee los datos y devuelve una secuencia de bytes. Datos, err := ioutil.ReadFile(nombre de archivo)
Escribir archivo Escribe datos en un archivo. l, errar := f.WriteString(text_to_write)

Resumir este post con: