Page cover

🐢Variable - Tipos de Datos

Que son las variables y por consiguiente los tipos de datos, ¿cuales hay en go? ¿que tipos de datos se usan más frecuentes? etc...

Referencia:

Referencia pagina donde aprendí y tome como base

Tipos de Datos en Go (Golang) ->

En Go, hay varios tipos de datos disponibles, que se pueden clasificar en cuatro categorías principales:

  1. Tipos de datos básicos:

    • bool: representa un valor booleano (true o false).

    • string: representa una cadena de texto.

    • int: representa un número entero.

    • float32 y float64: representan números en coma flotante.

  2. Tipos de datos compuestos:

    • array: representa una colección de elementos del mismo tipo.

    • slice: es similar a un array, pero su tamaño puede ser modificado dinámicamente.

    • map: representa una colección de pares clave-valor.

    • struct: representa un conjunto de campos con diferentes tipos de datos.

  3. Tipos de datos de referencia:

    • pointer: representa la dirección de memoria de una variable.

    • function: representa una función.

    • interface: define un conjunto de métodos que una estructura debe implementar.

  4. Tipos de datos especiales:

    • chan: se utiliza para la comunicación entre goroutines.

    • complex64 y complex128: representan números complejos.


Código ejemplificando un poco del curso Udemy →

package main

import (
"fmt"
)

func main() {
   var nombreVar int         //Esta es una forma de declarar una variable en Go.
   var nombreDecimal float64 //Decimal de tipo float64 bits
   var nombreTexto string    //string de tipo string
   var nombreBool bool       //variable de tipo booleana false or true
   
   nombreVar = 7
   nombreDecimal = 6.9
   nombreTexto = "Hola Mundo :)"
   nombreBool = true

   //Forma de declarar una variable sin definir el tipo de dato -> con ":="
   nombreNumero := 10

   fmt.Println(nombreVar, nombreDecimal, nombreTexto, nombreBool)
   fmt.Println(nombreNumero)
}

No se puede redefinir el valor de una variable luego de haber sido definida →

Es importante tener en cuenta que los tipos de datos básicos en Go son valores inmutables. Esto significa que una vez que se define su valor, no se puede cambiar. Si se desea actualizar el valor de una variable, se debe crear una nueva variable con el nuevo valor.

  • Linea 19 con Linea 24

  • Lo mismo pasa con querer intentar cambiar el tipo de dato de una variable que ya ha sido definida su tipo de dato, no se puede redefinir.

Tipos de datos compuestos en Go

uint8       unsigned  8-bit integers (0 to 255)
uint16      unsigned 16-bit integers (0 to 65535)
uint32      unsigned 32-bit integers (0 to 4294967295)
uint64      unsigned 64-bit integers (0 to 18446744073709551615)
int8        signed  8-bit integers (-128 to 127)
int16       signed 16-bit integers (-32768 to 32767)
int32       signed 32-bit integers (-2147483648 to 2147483647)
int64       signed 64-bit integers (-9223372036854775808 to 9223372036854775807)

float32     IEEE-754 32-bit floating-point numbers
float64     IEEE-754 64-bit floating-point numbers
complex64   complex numbers with float32 real and imaginary parts
complex128  complex numbers with float64 real and imaginary parts

byte        alias for uint8
rune        alias for int32

uint8: 100
uint16: 50000
uint32: 1000000000
uint64: 100000000000000
int8: -50
int16: -20000
int32: -100000000
int64: 100000000000000

Desglose de los otros tipos:

  • float32: Representa números de punto flotante de 32 bits.

  • float64: Representa números de punto flotante de 64 bits, que tienen mayor precisión.

  • complex64: Representa números complejos con partes reales e imaginarias de tipo float32.

  • complex128: Representa números complejos con partes reales e imaginarias de tipo float64.

  • byte: Es un alias para uint8, que puede contener valores de 0 a 255.

  • rune: Es un alias para int32, que se utiliza para representar un carácter Unicode. En el ejemplo, 'A' es el carácter que corresponde al valor 65 en Unicode.

En Go, los tipos de datos compuestos son tipos de datos que están formados por la combinación de uno o más valores de tipos de datos básicos.

El propósito del alias byte es dejar claro el momento en que el programa usa bytes a modo de medición informática común en elementos de cadenas de caracteres, en contraposición a enteros pequeños no relacionados con la medición de datos de byte. Aunque byte y uint8 son idénticos una vez que se compila el programa, byte se utiliza a menudo para representar datos de caracteres en formato numérico, mientras que uint8 está diseñado para ser un número en su programa.

El alias rune es un poco diferente. Si bien byte y uint8 contienen exactamente los mismos datos, un rune puede ser de un solo byte o de cuatro, un rango determinado por int32. Un rune se utiliza para representar un carácter Unicode, mientras que solo los caracteres ASCII se pueden representar únicamente con un tipo de datos int32.

Los tipos de datos compuestos disponibles en Go son

  1. Array: este tipo de datos representa una colección de elementos del mismo tipo. Los arrays en Go tienen una longitud fija que se define en el momento de la creación del array.

    // Declarar un array de tipo entero
    var numeros [5]int = [5]int{1, 2, 3, 4, 5}
    numeros2 := [2]int{1, 6}
    
    // Imprimir el valor de un elemento del array
    fmt.Println("Número 3:", numeros[2])
    fmt.Println("Número 6:", numeros[1])
  2. Slice: este tipo de datos es similar a un array, pero su tamaño puede ser modificado dinámicamente. Un slice se crea a partir de un array y se puede acceder a sus elementos utilizando la misma sintaxis que un array.

    	// Declarar un slice de tipo entero
    	var numeros3 []int = []int{1, 2, 3, 4, 5}
    	numeros33 := []int{11, 24, 36}
    	seaCreatures := []string{"shark", "cuttlefish", "squid", "mantis shrimp"}
    	[]float64{3.14, 9.23, 111.11, 312.12, 1.05}
    	[]string{"shark", "cuttlefish", "squid", "mantis shrimp"}
    
    	// Agregar un nuevo elemento al slice
    	numeros33 = append(numeros33, 190)
    
    	// Imprimir el valor de un elemento del slice
    	fmt.Println("Número 4:", numeros3[3])
    	fmt.Println("Número 190:", numeros33[3])
  3. Map: este tipo de datos representa una colección de pares clave-valor. Cada clave en el mapa debe ser única y el valor asociado puede ser de cualquier tipo de datos. Por ejemplo:

    1. La regla de oro es:

      Usar make para slices, maps y channels y new para valors numéricos, structs etc.

    // Declarar un map con claves de tipo cadena y valores de tipo entero
    var edades map[string]int = make(map[string]int{"Juan": 28, "Ana": 30})
    
    // Imprimir el valor asociado a una clave en el map
    fmt.Println("Edad de Ana:", edades["Ana"])

    Comprobación de la existencia de una clave:

    Se puede comprobar si una clave existe en un mapa utilizando la función len.

    
    _, ok := m["clave5"]
    if ok {
      // La clave existe
    } else {
      // La clave no existe
    }
    
    Lenguaje del código: Go (go)

    Recorrer un mapa:

    Se puede recorrer un mapa utilizando un bucle for.

    for clave, valor := range m {
      fmt.Println(clave, valor)
    }
  4. Struct: este tipo de datos representa un conjunto de campos con diferentes tipos de datos. Las estructuras se utilizan para agrupar diferentes tipos de datos en una única variable.

    // Declarar una estructura con diferentes campos
    type Persona struct {
       nombre string
       edad int
       altura float64
    }
    
    // Declarar una variable de tipo Persona
    var persona1 Persona = Persona{"Juan", 28, 1.75}
    
    // Imprimir el valor de un campo de la estructura
    fmt.Println("Edad de", persona1.nombre, ":", persona1.edad)

Es importante tener en cuenta que los tipos de datos compuestos en Go se utilizan para representar datos más complejos y estructurados en un programa.

Los arrays, slices, maps y struct se utilizan para agrupar diferentes tipos de datos en una única variable.


  1. Matrices: Una matriz es una secuencia ordenada de elementos. La capacidad de una matriz se define en el momento de su creación. Una vez que se asigna el tamaño a una matriz, este ya no se puede cambiar. Debido a que el tamaño de una matriz es estático, significa que se asigna memoria solo una vez. Esto hace que el trabajo con matrices resulte un tanto rígido, pero aumenta el rendimiento de su programa. Debido a esto, las matrices suelen utilizarse al optimizar programas. Los segmentos, que veremos a continuación, son más flexibles y constituyen lo que se podría considerar como matrices en otros lenguajes.

    Las matrices se definen al declarar el tamaño de estas y luego el tipo de datos con los valores definidos entre llaves { }.

    Una matriz de cadenas tiene el siguiente aspecto:

    var matriz [3][3]int = [3][3]int{
        {1, 2, 3},  // Fila 1
        {4, 5, 6},  // Fila 2
    }
    
    [3][3]string{
    {"blue coral", "staghorn coral", "pillar coral"},
    {"Cadena 4", "Cadena 5", "Cadena 6"},
    }
    
    //Tambien se puede almacenar una matriz en una variable e imprimirla: 
    matriz := [2][3]string{
    {"blue coral", "staghorn coral", "pillar coral"},
    {"Cadena 4", "Cadena 5", "Cadena 6"},
    }
    fmt.Println(matriz)

Como ya lo mencioné anteriormente, los segmentos son similares a las matrices, pero son mucho más flexibles. Veamos este tipo de datos mutable.


Tipos de datos de referencia en GO

Function:

  • este tipo de datos representa una función. Las funciones en Go son tipos de datos de primera clase, lo que significa que se pueden asignar a variables y pasar como argumentos a otras funciones, y que ademas dentro de la función se puede contener una cantidad de código que hará algo en especifico según la logica que se lleve.

  • Algo importante por saber en Go: El nombre de la función en Go debe comenzar con una letra minúscula para funciones no exportadas (privadas) o mayúscula para funciones exportadas (públicas), aqui lo noté porque cuando llamaba por fuera del main con minuscula no podía llamarse a la funcion pero cuando le cambiaba a MAY la primera letra ahi si se definía la function como publica.

    • Si el nombre de la función o variable comienza con minúscula, será privada al paquete donde se define. Solo puede ser accedida desde dentro de ese mismo paquete.

    • Si el nombre comienza con mayúscula, será exportada (pública) y puede ser accedida desde otros paquetes.

    • Por ejm: Declarar una funcion que sume 2 numeros:

    package main
    
    import "fmt"
    
    // Declarar una función que suma dos números
    func Suma(a,b int) int{
       return a + b
    }
    
    func main(){
    
         //Asignar la función a una variable
         var funcionSuma = Suma
         
         //Llamar a la función a través de la variable
         resultado := funcionSuma(1,3) //Return 5
    
         //Imprimir resultado
         fmt.Println("Resultado Suma: ", resultado)
    }

Pointer 💀

  • Este tipo de datos representa la dirección de memoria de una variable. Los punteros se utilizan para acceder y manipular el valor de una variable indirectamente, a través de su dirección de memoria.

    Uso del & y *

    • &: Lo usas para obtener la dirección de memoria de una variable. Es como decir: "Dame la ubicación donde está este valor en la memoria."

    • *: Lo usas para acceder al valor que está almacenado en esa dirección. Una vez que tienes la dirección (guardada en el puntero), puedes "desreferenciarla" con * para obtener el valor real en esa ubicación.

      x := 42         // `x` tiene el valor 42
      p := &x         // `p` guarda la dirección de memoria de `x`
      
      fmt.Println(*p) // `*p` accede al valor en la dirección, que es 42
      • Primero usas & para obtener la dirección (el puntero) y luego usas * para acceder al valor en esa dirección.

  • Rapidez: El puntero no necesita "buscar" el valor en la memoria una vez que tiene la dirección. Es más rápido acceder directamente a un valor a través de su puntero, especialmente cuando trabajas con estructuras grandes o datos en lugares específicos de la memoria.

    En resumen

    • El puntero (*) guarda la dirección de memoria donde está un valor, no el valor mismo.

    • El operador & obtiene la dirección de memoria de una variable.

    • El operador * desreferencia el puntero para acceder al valor en esa dirección.

    • Eficiencia: Usar punteros es útil para evitar copias innecesarias de grandes estructuras o arreglos, haciendo el acceso a los datos más rápido y eficiente.


En Go, cuando se recibe un argumento como puntero se suele comprobar si es nulo o no antes de realizar cualquier operación en él para evitar excepciones en el programa.

Esta técnica se usa con frecuencia para comprobar la presencia de nil:

if someVariable == nil {
	// print an error or return from the method or fuction
}

Interfaces:

Este tipo de datos define un conjunto de métodos que una estructura debe implementar. Las interfaces se utilizan para definir un comportamiento común que se puede compartir entre diferentes tipos de estructuras.

Lo que hace una interfaz es poder definir un conjunto de metodos que podemos usar para una estructura en su implementacion, basicamente poder integrarle metodos a una estructura mediante la interfaz.

// Declarar una interfaz que define un método para obtener el área
type Figura interface {
   Area() float64
}

// Declarar una estructura de tipo rectángulo
type Rectangulo struct {
   ancho float64
   alto  float64
}

// Declarar una estructura de tipo círculo
type Circulo struct {
   radio float64
}

// Implementar el método para obtener el área del rectángulo
func (r Rectangulo) Area() float64 {
   return r.ancho * r.alto
}

// Implementar el método para obtener el área del círculo
func (c Circulo) Area() float64 {
   return 3.1416 * c.radio * c.radio
}

// Declarar una función que recibe una figura y calcula su área
func ObtenerArea(figura Figura) float64 {
   return figura.Area()
}

// Crear una variable de tipo rectángulo y calcular su área
rectangulo := Rectangulo{ancho: 2, alto: 4}
areaRectangulo := ObtenerArea(rectangulo) //area: 8

// Crear una variable de tipo círculo y calcular su área
circulo := Circulo{radio: 3}
areaCirculo := ObtenerArea(circulo)

// Imprimir las áreas de las figuras
fmt.Println("Área del rectángulo:", areaRectangulo)
fmt.Println("Área del círculo:", areaCirculo)

Es importante tener en cuenta que los tipos de datos de referencia en Go se utilizan para representar datos que no están directamente almacenados en una variable, sino que se encuentran en una ubicación de memoria separada.

Los punteros se utilizan para acceder a la ubicación de memoria y manipular el valor de una variable indirectamente. Las funciones se utilizan para encapsular un comportamiento y reutilizarlo en diferentes partes del programa.

Las interfaces se utilizan para definir un comportamiento común que se puede compartir entre diferentes tipos de estructuras.

Last updated