Go (o Golang) es un lenguaje de programación desarrollado por Google en 2009. Combina la eficiencia de los lenguajes compilados con la facilidad de uso de los lenguajes interpretados.
package main
import "fmt"
func main() {
fmt.Println("¡Hola, Mundo!")
}
# Descargar la última versión de Go
wget https://golang.org/dl/go1.19.linux-amd64.tar.gz
# Extraer el archivo en /usr/local
sudo tar -C /usr/local -xzf go1.19.linux-amd64.tar.gz
# Configurar variables de entorno
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile
echo 'export GOPATH=$HOME/go' >> ~/.profile
echo 'export PATH=$PATH:$GOPATH/bin' >> ~/.profile
# Recargar el perfil
source ~/.profile
# Verificar instalación
go version
La estructura recomendada para proyectos en Go:
~/go/
├── bin/ # Ejecutables instalados
├── pkg/ # Paquetes compilados
└── src/ # Código fuente
└── github.com/
└── tu-usuario/
└── mi-proyecto/
Nota: A partir de Go 1.11, puedes usar módulos fuera del GOPATH con go mod init
.
package main
import "fmt"
func main() {
// Declaración con tipo explícito
var nombre string = "Juan"
// Declaración con inferencia de tipo
edad := 30
// Constantes
const pi = 3.1416
// Tipos básicos
var activo bool = true
var salario float64 = 1500.50
var codigo rune = 'A' // alias para int32 (Unicode)
fmt.Printf("Nombre: %s, Edad: %d, Activo: %t\n", nombre, edad, activo)
}
// If-else
if edad >= 18 {
fmt.Println("Mayor de edad")
} else {
fmt.Println("Menor de edad")
}
// Switch
switch diaSemana {
case 1:
fmt.Println("Lunes")
case 2:
fmt.Println("Martes")
default:
fmt.Println("Otro día")
}
// For (el único bucle en Go)
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// For como while
n := 1
for n < 100 {
n *= 2
}
// Función básica
func suma(a int, b int) int {
return a + b
}
// Múltiples valores de retorno
func divide(a, b float64) (float64, error) {
if b == 0.0 {
return 0.0, fmt.Errorf("no se puede dividir por cero")
}
return a / b, nil
}
// Función con parámetros variables
func promedios(numeros ...float64) float64 {
total := 0.0
for _, num := range numeros {
total += num
}
return total / float64(len(numeros))
}
type Empleado struct {
ID int
Nombre string
Puesto string
Salario float64
Activo bool
}
// Método para la estructura Empleado
func (e Empleado) MostrarInfo() {
fmt.Printf("ID: %d\nNombre: %s\nPuesto: %s\nSalario: %.2f\n",
e.ID, e.Nombre, e.Puesto, e.Salario)
}
// Método con receptor por puntero para modificar la estructura
func (e *Empleado) AumentarSalario(porcentaje float64) {
e.Salario *= (1 + porcentaje/100)
}
func main() {
emp := Empleado{
ID: 1,
Nombre: "María López",
Puesto: "Desarrolladora Backend",
Salario: 45000,
Activo: true,
}
emp.MostrarInfo()
emp.AumentarSalario(10)
emp.MostrarInfo()
}
package main
import (
"fmt"
"time"
)
func tarea(nombre string, segundos int) {
fmt.Printf("Tarea %s iniciada\n", nombre)
time.Sleep(time.Duration(segundos) * time.Second)
fmt.Printf("Tarea %s completada\n", nombre)
}
func main() {
// Ejecución secuencial
tarea("A", 2)
tarea("B", 1)
// Ejecución concurrente con goroutines
go tarea("C", 3)
go tarea("D", 2)
// Esperar para que no termine el programa
time.Sleep(4 * time.Second)
}
func procesarPedido(id int, ch chan<- string) {
tiempo := time.Duration(rand.Intn(3)+1) * time.Second
time.Sleep(tiempo)
ch <- fmt.Sprintf("Pedido %d procesado en %v", id, tiempo)
}
func main() {
rand.Seed(time.Now().UnixNano())
// Crear channel
ch := make(chan string)
// Iniciar 5 goroutines
for i := 1; i <= 5; i++ {
go procesarPedido(i, ch)
}
// Recibir resultados
for i := 1; i <= 5; i++ {
fmt.Println(<-ch)
}
}
// Worker que procesa tareas
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Printf("Worker %d procesando job %d\n", id, j)
time.Sleep(time.Second) // Simular trabajo
results <- j * 2 // Enviar resultado
}
}
func main() {
const numJobs = 10
const numWorkers = 3
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)
// Iniciar workers
for w := 1; w <= numWorkers; w++ {
go worker(w, jobs, results)
}
// Enviar trabajos
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
// Recibir resultados
for a := 1; a <= numJobs; a++ {
<-results
}
}
// Leer archivo completo
func leerArchivo(ruta string) (string, error) {
contenido, err := os.ReadFile(ruta)
if err != nil {
return "", err
}
return string(contenido), nil
}
// Escribir archivo
func escribirArchivo(ruta, contenido string) error {
return os.WriteFile(ruta, []byte(contenido), 0644)
}
// Leer archivo línea por línea
func leerLineas(ruta string) ([]string, error) {
file, err := os.Open(ruta)
if err != nil {
return nil, err
}
defer file.Close()
var lineas []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lineas = append(lineas, scanner.Text())
}
return lineas, scanner.Err()
}
// Ejecutar comando y obtener salida
func ejecutarComando(cmd string, args ...string) (string, error) {
output, err := exec.Command(cmd, args...).CombinedOutput()
return string(output), err
}
// Ejemplo: monitorear uso de disco
func espacioDisco() (string, error) {
return ejecutarComando("df", "-h")
}
// Ejemplo: listar procesos
func listarProcesos() (string, error) {
return ejecutarComando("ps", "aux")
}
package main
import (
"fmt"
"os/exec"
"runtime"
"time"
)
type MetricasSistema struct {
Uptime string
MemoriaLibre string
CPU string
Discos string
}
func obtenerMetricas() (MetricasSistema, error) {
var m MetricasSistema
var err error
// Obtener uptime
m.Uptime, err = ejecutarComando("uptime", "-p")
if err != nil {
return m, err
}
// Obtener memoria libre (Linux)
if runtime.GOOS == "linux" {
m.MemoriaLibre, err = ejecutarComando("free", "-h")
} else {
m.MemoriaLibre = "Solo disponible en Linux"
}
// Obtener uso de CPU (Linux)
if runtime.GOOS == "linux" {
m.CPU, err = ejecutarComando("top", "-bn1")
} else {
m.CPU = "Solo disponible en Linux"
}
// Obtener espacio en disco
m.Discos, err = ejecutarComando("df", "-h")
return m, err
}
func main() {
for {
metricas, err := obtenerMetricas()
if err != nil {
fmt.Printf("Error al obtener métricas: %v\n", err)
continue
}
fmt.Println("\n=== Monitor del Sistema ===")
fmt.Println("Uptime:", metricas.Uptime)
fmt.Println("Memoria Libre:\n", metricas.MemoriaLibre)
fmt.Println("Uso de CPU:\n", metricas.CPU)
fmt.Println("Espacio en disco:\n", metricas.Discos)
time.Sleep(5 * time.Second)
}
}
func hacerPeticion(url string) (string, error) {
resp, err := http.Get(url)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("código de estado: %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(body), nil
}
// Ejemplo con contexto y timeout
func hacerPeticionConTimeout(url string, timeout time.Duration) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return "", err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(body), nil
}
func manejadorSaludo(w http.ResponseWriter, r *http.Request) {
nombre := r.URL.Query().Get("nombre")
if nombre == "" {
nombre = "Visitante"
}
fmt.Fprintf(w, "¡Hola, %s!", nombre)
}
func manejadorAPI(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
fmt.Fprintf(w, `{"mensaje": "Hola desde GET"}`)
case "POST":
var data map[string]interface{}
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
fmt.Fprintf(w, `{"recibido": %v}`, data)
default:
http.Error(w, "Método no permitido", http.StatusMethodNotAllowed)
}
}
func main() {
// Configurar rutas
http.HandleFunc("/saludo", manejadorSaludo)
http.HandleFunc("/api", manejadorAPI)
// Servir archivos estáticos
fs := http.FileServer(http.Dir("static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
// Iniciar servidor
fmt.Println("Servidor iniciado en http://localhost:8080")
http.ListenAndServe(":8080", nil)
}
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
type Producto struct {
ID string `json:"id"`
Nombre string `json:"nombre"`
Precio float64 `json:"precio"`
}
var productos = []Producto{
{ID: "1", Nombre: "Laptop", Precio: 1200.99},
{ID: "2", Nombre: "Teléfono", Precio: 599.50},
}
func main() {
router := gin.Default()
// Grupo de rutas /api/v1
v1 := router.Group("/api/v1")
{
v1.GET("/productos", obtenerProductos)
v1.GET("/productos/:id", obtenerProducto)
v1.POST("/productos", crearProducto)
v1.PUT("/productos/:id", actualizarProducto)
v1.DELETE("/productos/:id", eliminarProducto)
}
router.Run(":8080")
}
func obtenerProductos(c *gin.Context) {
c.JSON(http.StatusOK, productos)
}
func obtenerProducto(c *gin.Context) {
id := c.Param("id")
for _, p := range productos {
if p.ID == id {
c.JSON(http.StatusOK, p)
return
}
}
c.JSON(http.StatusNotFound, gin.H{"error": "Producto no encontrado"})
}
func crearProducto(c *gin.Context) {
var nuevo Producto
if err := c.ShouldBindJSON(&nuevo); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
productos = append(productos, nuevo)
c.JSON(http.StatusCreated, nuevo)
}
package main
import (
"github.com/gin-gonic/gin"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type Ticket struct {
gorm.Model
Titulo string `json:"titulo"`
Descripcion string `json:"descripcion"`
Estado string `json:"estado"` // Abierto, En progreso, Cerrado
Prioridad string `json:"prioridad"` // Baja, Media, Alta
AsignadoA string `json:"asignado_a"`
}
func main() {
// Configurar base de datos SQLite
db, err := gorm.Open(sqlite.Open("tickets.db"), &gorm.Config{})
if err != nil {
panic("Error al conectar con la base de datos")
}
db.AutoMigrate(&Ticket{})
router := gin.Default()
// Middleware para inyectar la base de datos
router.Use(func(c *gin.Context) {
c.Set("db", db)
c.Next()
})
// Rutas para tickets
router.GET("/tickets", listarTickets)
router.POST("/tickets", crearTicket)
router.GET("/tickets/:id", obtenerTicket)
router.PUT("/tickets/:id", actualizarTicket)
router.DELETE("/tickets/:id", eliminarTicket)
router.Run(":8080")
}
func listarTickets(c *gin.Context) {
db := c.MustGet("db").(*gorm.DB)
var tickets []Ticket
if err := db.Find(&tickets).Error; err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, tickets)
}
func crearTicket(c *gin.Context) {
db := c.MustGet("db").(*gorm.DB)
var ticket Ticket
if err := c.ShouldBindJSON(&ticket); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
ticket.Estado = "Abierto" // Estado por defecto
if err := db.Create(&ticket).Error; err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(201, ticket)
}
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/mattn/go-sqlite3"
)
type Empleado struct {
ID int
Nombre string
Puesto string
Salario float64
}
func main() {
// Conectar a SQLite (creará el archivo si no existe)
db, err := sql.Open("sqlite3", "./empresa.db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Crear tabla
crearTabla := `
CREATE TABLE IF NOT EXISTS empleados (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nombre TEXT NOT NULL,
puesto TEXT,
salario REAL
);`
_, err = db.Exec(crearTabla)
if err != nil {
log.Fatal(err)
}
// Insertar datos
insertar := `INSERT INTO empleados (nombre, puesto, salario) VALUES (?, ?, ?)`
_, err = db.Exec(insertar, "Ana García", "Desarrolladora", 45000.50)
if err != nil {
log.Fatal(err)
}
// Consultar datos
filas, err := db.Query("SELECT id, nombre, puesto, salario FROM empleados")
if err != nil {
log.Fatal(err)
}
defer filas.Close()
var empleados []Empleado
for filas.Next() {
var e Empleado
err = filas.Scan(&e.ID, &e.Nombre, &e.Puesto, &e.Salario)
if err != nil {
log.Fatal(err)
}
empleados = append(empleados, e)
}
fmt.Printf("%+v\n", empleados)
}
package main
import (
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type Producto struct {
gorm.Model
Codigo string `gorm:"uniqueIndex;size:50"`
Nombre string `gorm:"size:100;not null"`
Precio float64 `gorm:"type:decimal(10,2)"`
Stock int `gorm:"default:0"`
Categoria string `gorm:"size:50"`
Disponible bool `gorm:"default:true"`
}
func main() {
// Configurar conexión PostgreSQL
dsn := "host=localhost user=postgres password=secret dbname=tienda port=5432 sslmode=disable"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic("Error al conectar con la base de datos")
}
// Migrar el esquema
db.AutoMigrate(&Producto{})
// Crear registro
producto := Producto{
Codigo: "PROD-001",
Nombre: "Laptop Elite",
Precio: 1299.99,
Stock: 15,
Categoria: "Electrónicos",
}
db.Create(&producto)
// Consultar
var productoEncontrado Producto
db.First(&productoEncontrado, "codigo = ?", "PROD-001")
// Actualizar
db.Model(&productoEncontrado).Update("Precio", 1199.99)
// Eliminar
// db.Delete(&productoEncontrado)
}
Comando | Descripción |
---|---|
go build |
Compilar el proyecto |
go run main.go |
Compilar y ejecutar |
go test ./... |
Ejecutar tests |
go mod init |
Inicializar módulo |
go get paquete |
Instalar dependencia |
go fmt ./... |
Formatear código |
go vet ./... |
Buscar posibles errores |
package main
import (
"testing"
)
func Sumar(a, b int) int {
return a + b
}
func TestSumar(t *testing.T) {
pruebas := []struct {
nombre string
a, b int
esperado int
}{
{"positivos", 2, 3, 5},
{"negativos", -1, -1, -2},
{"mezclados", -5, 5, 0},
{"cero", 0, 0, 0},
}
for _, prueba := range pruebas {
t.Run(prueba.nombre, func(t *testing.T) {
resultado := Sumar(prueba.a, prueba.b)
if resultado != prueba.esperado {
t.Errorf("Sumar(%d, %d) = %d; esperado %d",
prueba.a, prueba.b, resultado, prueba.esperado)
}
})
}
}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"time"
"github.com/hibiken/asynq"
)
// Estructura para los mensajes
type EmailTask struct {
ID string `json:"id"`
Recipient string `json:"recipient"`
Subject string `json:"subject"`
Body string `json:"body"`
}
// Procesador de tareas
func handleEmailTask(ctx context.Context, t *asynq.Task) error {
var email EmailTask
if err := json.Unmarshal(t.Payload(), &email); err != nil {
return fmt.Errorf("error al decodificar payload: %v", err)
}
log.Printf("Enviando email a %s: %s", email.Recipient, email.Subject)
time.Sleep(2 * time.Second) // Simular envío
log.Printf("Email enviado correctamente (ID: %s)", email.ID)
return nil
}
func main() {
// Configurar Redis (para la cola)
redis := asynq.RedisClientOpt{
Addr: "localhost:6379",
}
// Crear servidor de workers
srv := asynq.NewServer(
redis,
asynq.Config{
Concurrency: 10, // Número máximo de workers concurrentes
Queues: map[string]int{
"emails": 6, // Prioridad alta
"default": 3,
"low": 1,
},
},
)
// Mux para manejar diferentes tipos de tareas
mux := asynq.NewServeMux()
mux.HandleFunc("email:send", handleEmailTask)
// Iniciar servidor
if err := srv.Run(mux); err != nil {
log.Fatalf("Error al iniciar el servidor: %v", err)
}
}
package main
import (
"bytes"
"context"
"fmt"
"log"
"net/http"
"os"
"time"
"cloud.google.com/go/storage"
"github.com/gin-gonic/gin"
"google.golang.org/api/option"
)
type FileRequest struct {
FileName string `json:"file_name" binding:"required"`
Content string `json:"content" binding:"required"`
}
func main() {
// Configurar cliente de Google Cloud Storage
ctx := context.Background()
client, err := storage.NewClient(ctx, option.WithCredentialsFile("credentials.json"))
if err != nil {
log.Fatalf("Error al crear cliente GCS: %v", err)
}
defer client.Close()
bucketName := os.Getenv("GCS_BUCKET")
if bucketName == "" {
bucketName = "mi-bucket-procesamiento"
}
router := gin.Default()
router.POST("/procesar", func(c *gin.Context) {
var req FileRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Procesar contenido (ejemplo: convertir a mayúsculas)
processedContent := bytes.ToUpper([]byte(req.Content))
// Subir a Google Cloud Storage
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
obj := client.Bucket(bucketName).Object(req.FileName)
w := obj.NewWriter(ctx)
if _, err := w.Write(processedContent); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
if err := w.Close(); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Generar URL pública (opcional)
attrs, err := obj.Attrs(ctx)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "Archivo procesado y almacenado",
"file_name": req.FileName,
"size_bytes": attrs.Size,
"url": fmt.Sprintf("https://storage.googleapis.com/%s/%s", bucketName, req.FileName),
})
})
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
log.Printf("Servidor de procesamiento iniciado en :%s", port)
router.Run(":" + port)
}