1 Introducción a los tipos de datos en el lenguaje Go

En el lenguaje Go, los tipos de datos son la base de la programación, determinando la forma de los datos que las variables pueden almacenar. Los tipos de datos básicos proporcionados por el lenguaje Go se dividen principalmente en las siguientes categorías:

Tipo de dato Descripción Uso de memoria
bool Tipo booleano, utilizado para almacenar verdadero o falso 1 byte
int, uint Enteros con y sin signo, el tamaño predeterminado depende de la plataforma del sistema 4 o 8 bytes
int8, uint8 Enteros con y sin signo de 8 bits 1 byte
int16, uint16 Enteros con y sin signo de 16 bits 2 bytes
int32, uint32 Enteros con y sin signo de 32 bits 4 bytes
int64, uint64 Enteros con y sin signo de 64 bits 8 bytes
float32 Número de punto flotante de 32 bits 4 bytes
float64 Número de punto flotante de 64 bits 8 bytes
complex64 Número complejo con partes reales e imaginarias de 32 bits 8 bytes
complex128 Número complejo con partes reales e imaginarias de 64 bits 16 bytes
byte Similar a uint8 1 byte
rune Similar a int32, representa un punto de código Unicode 4 bytes
string Tipo cadena de texto Dependiente de la longitud de la cadena
error Interfaz de error, utilizada para devolver información de error Sin tamaño fijo

Estos tipos pueden ser elegidos según diferentes necesidades, como cálculos numéricos, procesamiento de texto o control lógico.

2 Tipos de datos enteros

2.1 Visión general de los tipos enteros

El lenguaje Go tiene varios tipos enteros incorporados, clasificados de la siguiente manera:

  • Enteros con signo: int8, int16, int32 (o rune), int64, e int
  • Enteros sin signo: uint8 (o byte), uint16, uint32, uint64, y uint

Los tamaños de int y uint son de 4 bytes en sistemas de 32 bits y de 8 bytes en sistemas de 64 bits. Los rangos de valores de los tipos de datos enteros se muestran en la siguiente tabla:

Tipo Rango de valores
int8 -128 a 127
uint8 0 a 255
int16 -32768 a 32767
uint16 0 a 65535
int32 -2147483648 a 2147483647
uint32 0 a 4294967295
int64 -9223372036854775808 a 9223372036854775807
uint64 0 a 18446744073709551615

2.2 Uso de variables enteras

La sintaxis básica para declarar una variable entera es la siguiente:

var nombre_variable tipo_de_dato = valor_inicial

Código de ejemplo:

package main
import "fmt"

func main() {
    var a int = 10 // Variable entera con signo
    var b uint = 20 // Variable entera sin signo
    var c int8 = -128 // Valor más pequeño de int8
    fmt.Println(a, b, c)
}

2.3 Operaciones enteras

El lenguaje Go soporta operadores aritméticos comunes, como la suma (+), resta (-), multiplicación (*), división (/), y módulo (%), así como operadores a nivel de bits como el AND a nivel de bits (&), OR (|), XOR (^), desplazamiento a la izquierda (<<), y desplazamiento a la derecha (>>).

package main
import "fmt"

func main() {
    x := 10
    y := 3

    // Operaciones aritméticas
    fmt.Println(x + y) // Suma
    fmt.Println(x - y) // Resta
    fmt.Println(x * y) // Multiplicación
    fmt.Println(x / y) // División
    fmt.Println(x % y) // Módulo

    // Operaciones a nivel de bits
    fmt.Println(x & y)  // AND a nivel de bits
    fmt.Println(x | y)  // OR a nivel de bits
    fmt.Println(x ^ y)  // XOR a nivel de bits
    fmt.Println(x << 1) // Desplazamiento a la izquierda por 1
    fmt.Println(x >> 1) // Desplazamiento a la derecha por 1
}

3 Tipos de datos de punto flotante

3.1 Visión general de los tipos de datos de punto flotante

En el lenguaje Go, los tipos de punto flotante incluyen float32 y float64, correspondientes a datos de punto flotante de 32 bits y 64 bits. En general, se recomienda utilizar float64 ya que proporciona un rango más grande y una precisión más precisa.

  • float32 tiene aproximadamente 23 bits significativos, lo que proporciona alrededor de 7 dígitos decimales de precisión.
  • float64 tiene aproximadamente 52 bits significativos, lo que proporciona alrededor de 16 dígitos decimales de precisión.

3.2 Uso de variables de punto flotante

Las variables de punto flotante se pueden declarar directamente proporcionando literales o utilizando la palabra clave var:

package main
import "fmt"

func main() {
    var f1 float32 = 3.14 // Especificar explícitamente el tipo float32
    f2 := 3.14            // Inferido automáticamente como tipo float64
    fmt.Println(f1, f2)
}

3.3 Aritmética de punto flotante y problemas

La aritmética de punto flotante puede llevar a la pérdida de precisión. Realizar operaciones con una precisión muy alta es un problema común, especialmente al restar dos números muy cercanos.

package main
import "fmt"

func main() {
    f1 := .1
    f2 := .2
    f3 := f1 + f2
    fmt.Println(f3) // La salida puede no ser el .3 esperado debido a problemas de precisión

    // Solucionar problemas de precisión utilizando salida formateada
    fmt.Printf("%.1f\n", f3) // Salida corregida a .3
}

4 Tipo de dato booleano

4.1 Visión general del tipo de dato booleano

Booleano es el tipo de dato más simple y solo puede tener dos valores: true (verdadero) y false (falso). Ocupa una posición muy importante en las declaraciones condicionales y las estructuras de control de bucles.

4.2 Uso de variables booleanas

Declarar y usar variables booleanas:

package main
import "fmt"

func main() {
    var exito bool = true
    var fallido bool = false
    fmt.Println("Operación exitosa:", exito)
    fmt.Println("Operación fallida:", fallido)
}

Los valores booleanos a menudo se utilizan en declaraciones condicionales:

package main
import "fmt"

func main() {
    a := 10
    b := 20
    fmt.Println("a == b:", a == b) // falso
    fmt.Println("a < b:", a < b)   // verdadero
}

5 Tipo de dato cadena

5.1 Visión general de la cadena

Una cadena es una colección de caracteres. En el lenguaje Go, las cadenas son inmutables. Cada cadena consta de dos partes: un puntero al arreglo de bytes subyacente y una longitud. Las cadenas pueden contener cualquier dato, incluidos bytes.

5.2 Uso de variables de cadena

Las variables de cadena generalmente se declaran utilizando comillas dobles " para crear, pero también puedes usar comillas invertidas ` para crear cadenas de varias líneas:

package main
import "fmt"

func main() {
    var s1 string = "hola"
    s2 := "mundo"
    s3 := `Esto es una
    cadena de 
    varias líneas`
    fmt.Println(s1)
    fmt.Println(s2)
    fmt.Println(s3)
}

Una vez que se crea una cadena, su contenido no se puede cambiar. La siguiente operación es ilegal y provocará un error de compilación:

s := "hola"
s[] = 'H` // Error de compilación: el contenido de la cadena es inmutable

5.3 Operaciones de cadena

Las cadenas son muy comunes e importantes en la programación. El lenguaje Go proporciona un conjunto rico de funciones integradas para la manipulación de cadenas. Aquí tienes algunas operaciones comúnmente utilizadas.

5.3.1 Concatenación de cadenas

En el lenguaje Go, puedes usar el operador más (+) para concatenar cadenas, que es el método más directo. Además, al tratar con la concatenación frecuente de múltiples cadenas, se recomienda utilizar strings.Builder para un mejor rendimiento.

package main

import (
    "fmt"
    "strings"
)

func main() {
    // Concatenar cadenas utilizando +
    hola := "¡Hola, "
    mundo := "Mundo!"
    resultado := hola + mundo
    fmt.Println(resultado) // Salida: ¡Hola, Mundo!

    // Concatenar cadenas utilizando strings.Builder
    var sb strings.Builder
    sb.WriteString("¡Hola, ")
    sb.WriteString("Mundo!")
    fmt.Println(sb.String()) // Salida: ¡Hola, Mundo!
}

5.3.2 División de cadenas

La división de cadenas se puede realizar utilizando la función strings.Split, la cual divide la cadena en una lista basada en el delimitador especificado.

paquete principal

import (
	"fmt"
	"strings"
)

func main() {
	// Definir una cadena
	oración := "Go es un lenguaje de programación de código abierto"

	// Dividir la cadena por el espacio
	palabras := strings.Split(oración, " ")
	para _, palabra := rango palabras {
		fmt.Printf("%s\n", palabra)
	}
	// Salida:
	// Go
	// es
	// un
	// lenguaje
	// de
	// programación
	// código
	// abierto
}

5.3.3 Acceso por índice

En Go, una cadena es una secuencia inmutable de bytes. Puedes usar índices para acceder a bytes específicos en una cadena. Sin embargo, es importante tener en cuenta que debido a que una cadena puede contener caracteres de varios bytes (como caracteres codificados en UTF-8), acceder directamente a ellos puede no devolver el carácter único esperado.

paquete principal

import "fmt"

func main() {
	s := "Hola, 世界"
	para i := 0; i < len(s); i++ {
		fmt.Printf("%d: %x\n", i, s[i])
	}
	// Nota: esto mostrará la representación hexadecimal de los bytes, no los caracteres
}

Para iterar a través de la cadena por carácter, puedes usar el bucle range.

paquete principal

import "fmt"

func main() {
	s := "Hola, 世界"
	para índice, valorRune := rango s {
		fmt.Printf("%d: %U '%c'\n", índice, valorRune, valorRune)
	}
	// Salida: índice, codificación Unicode y el carácter en sí para cada carácter
}

5.3.4 Obteniendo la longitud

La función len puede obtener la longitud de una cadena, es decir, la longitud de la secuencia de bytes subyacente. Para cadenas UTF-8, si necesitas obtener el número de caracteres (runas), debes usar la función utf8.RuneCountInString. Esto puede manejar correctamente los caracteres de varios bytes.

paquete principal

import (
	"fmt"
	"unicode/utf8"
)

func main() {
	s := "Hola, 世界"
	fmt.Println("Longitud en bytes:", len(s)) // Muestra la longitud de bytes
	fmt.Println("Longitud en runas:", utf8.RuneCountInString(s)) // Muestra la longitud de caracteres
}

Desde el ejemplo anterior, podemos ver que el lenguaje Go proporciona funciones de biblioteca completas para operaciones de cadena, facilitando la realización de diversas tareas de procesamiento de cadenas. Al codificar, es importante prestar atención a la distinción entre bytes y caracteres, especialmente al tratar con conjuntos de caracteres no ASCII.