1. Fundamentos de Go (120 preguntas)
Sintaxis y semántica (30 preguntas)
1. ¿Cuál es el valor cero de un mapa en Go?
Por qué:
Comprender los valores cero evita problemas de ejecución causados por mapas no inicializados.
Qué:
- El valor cero de un mapa es
nil. - Un mapa nulo no puede contener pares clave-valor.
Cómo:
var m map[string]int // m == nil
m = make(map[string]int) // inicializar
m["age"] = 30 // ahora funciona
Caso de uso en la vida real:
Un mapa nulo podría representar un objeto de configuración sin inicializar. Una inicialización correcta evita fallos al agregar configuraciones.
2. ¿Cómo maneja Go la conversión de tipo implícita entre int y float64?
Por qué:
Go aplica una tipificación estricta para evitar la pérdida accidental de datos.
Qué:
- No hay conversión implícita entre tipos numéricos.
- Se requiere casting explícito.
Cómo:
i := 42
f := float64(i) // conversión explícita
i = int(f) // volver a int (trunca el decimal)
Caso de uso en la vida real:
Conversión de lecturas de sensores (enteros) a valores de punto flotante para cálculos científicos.
3. Escribe el código para declarar constantes para los días de la semana usando iota.
Por qué:
iota simplifica las declaraciones de constantes secuenciales.
Qué:
- iota se incrementa automáticamente desde 0 en un bloque de constantes.
Cómo:
const(
Sunday = iota // 0
Monday // 1
Tuesday // 2
// ... hasta Saturday (6))
Caso de uso en la vida real:
Representar días en sistemas de programación (por ejemplo, aplicaciones de calendario).
4. Explica la diferencia entre var x int = 10 y x := 10.
Por qué:
Elegir el estilo de declaración correcto afecta la legibilidad y el alcance del código.
Qué:
- var x int = 10: Declaración de tipo explícita, funciona en cualquier ámbito.
- x := 10: Inferencia de tipos, solo dentro de funciones.
Cómo:
varglobalVar int = 10 // nivel de paquete
funcmain(){
localVar := 20 // nivel de función
}
Caso de uso en la vida real:
Usando var para constantes a nivel de paquete y := para variables de bucle local.
5. ¿Por qué Go no permite variables o importaciones no utilizadas?
Por qué:
Go prioriza el código limpio y eficiente y la seguridad en tiempo de compilación.
Qué:
- Las variables/importaciones no utilizadas indican posibles errores o inflación.
- El compilador lanza errores para forzar la limpieza.
Cómo:
// Error: unused import "fmt"
// Error: unused variable x
import"fmt"
func main() {
x := 10
}
Caso de uso en la vida real:
Evitar que las variables de depuración sobrantes se envíen a producción.
6. ¿Cómo se crea una cadena de varias líneas sin caracteres de escape?
Por qué:
Las cadenas sin formato mejoran la legibilidad de las plantillas o JSON.
Qué:
- Utilice comillas invertidas ` para literales de cadena sin formato.
Cómo:
s :=`Line 1
Line 2
Line 3`
Caso de uso en la vida real:
Incrustar consultas SQL o plantillas HTML en el código.
7. ¿Cuál es el propósito del _ (identificador en blanco) en los bucles for?
Por qué:
Ignora los valores que no necesitas, evitando las advertencias del compilador.
Qué:
- Omite el índice o valor en bucles de rango.
Cómo:
for _, value := range []int{1,2,3} {
fmt.Println(value) // ignorar indice
}
Caso de uso en la vida real:
Procesamiento de elementos de slices sin necesidad de conocer sus posiciones.
8. ¿Cómo maneja Go el desbordamiento de int8?
Por qué:
El manejo de desbordamientos afecta la integridad de los datos en sistemas de bajo nivel.
Qué:
- Se envuelve usando aritmética de complemento a dos.
Cómo:
var a int8 = 127
a++ // -128 (desbordamiento)
Caso de uso en la vida real:
Manejo de datos de sensores que exceden los límites del hardware.
9. ¿Cuál es la salida de fmt.Printf("%T", 'a')?
Por qué:
Comprender el tipo de runa de Go es clave para el manejo de Unicode.
Qué:
- 'a' es una runa (alias para int32).
Cómo:
fmt.Printf("%T",'a') // salida: int32
Caso de uso en la vida real:
Procesamiento de texto multilingüe (por ejemplo, emojis en la entrada del usuario).
10. ¿Cómo se define un alias de tipo personalizado para int?
Por qué:
Los alias de tipo mejoran la claridad del código y evitan el uso indebido.
Qué:
- Utilizar type NewName ExistingType.
Cómo:
type UserID int
var id UserID =1001
Caso de uso en la vida real:
Distinguir los identificadores de bases de datos de los números enteros regulares.
11. ¿Cuál es el valor cero de un slice?
Por qué:
Conocer el estado predeterminado de un slice evita errores de tiempo de ejecución cuando se manipulan datos no inicializados.
Qué:
- El valor cero de un slice es nil. Un slice nil tiene una longitud y una capacidad de 0.
Cómo:
var s []int // s == nil
s = make([]int, 3) // inicializar con longitud 3
Caso de uso en la vida real:
Comprobar si un slice es nulo antes de agregar datos en las respuestas de la API para evitar un comportamiento inesperado.
12. ¿Cómo se declara una variable sin inicializarla?
Por qué:
Las variables deben declararse antes de su uso, pero la inicialización puede posponerse.
Qué:
- Use "var" sin asignación. La variable obtiene su valor cero.
Cómo:
var count int // count = 0
var name string // name = ""
Caso de uso en la vida real:
Declaración de variables de configuración que se completan posteriormente mediante la entrada del usuario.
13. ¿Por qué no puedes usar ++x en Go (solo x++)?
Por qué:
Go elimina la ambigüedad al restringir el incremento/decremento a la notación sufija.
Qué:
- x++ es válido (postfijo).
- ++x no es válido (prefijo).
Cómo:
x := 5
x++ // valido (x = 6)
// ++x // error de compilación
Caso de uso en la vida real:
Evitar efectos secundarios en expresiones como y = x++ + 5, que no están permitidos en Go.
14. Escribir código para intercambiar dos variables sin una variable temporal.
Por qué:
Esto evita la sobrecarga de memoria para intercambios simples.
Qué:
- Utilizar aritmética o asignación de tuplas.
Cómo:
a, b := 10, 20
a, b = b, a // intercambio de tuplas (a=20, b=10)
Caso de uso en la vida real:
Intercambio de valores en algoritmos de ordenamiento (por ejemplo, ordenamiento de burbuja).
15. ¿Cómo maneja Go la división de dos números enteros?
Por qué:
Go sigue las reglas de división de números enteros, descartando el resto.
Qué:
- 3/2 equivale a 1 (no 1.5).
- Utilizar tipos flotantes para conservar decimales.
Cómo:
fmt.Println(3/2) // 1
fmt.Println(3.0/2.0) // 1.5
Caso de uso en la vida real:
Cálculo de puntuaciones medias donde la precisión decimal importa.
16. ¿Cuál es la diferencia entre string y []byte?
Por qué:
Los string son inmutables; []byte es mutable. Elegir el tipo correcto afecta el rendimiento y la seguridad.
Qué:
- string: secuencia UTF-8 inmutable.
- []byte: bytes sin procesar mutables.
Cómo:
s := "hello"
b := []byte(s) // convertir a bytes mutables
b[0]='H'
s = string(b) // "Hello"
Caso de uso en la vida real:
Modificación de datos binarios (por ejemplo, procesamiento de imágenes).
17. ¿Cómo se convierte un valor bool en un string?
Por qué:
La conversión de valores booleanos en string es útil para el registro o la visualización de la interfaz de usuario.
Qué:
- Utilice fmt.Sprintf o un condicional.
Cómo:
b :=true
s1 := fmt.Sprintf("%t", b) // "true"
s2 := "false"; if b { s2 ="true" }
Caso de uso en la vida real:
Mostrar “Sí/No” en una interfaz de usuario basada en un indicador booleano.
18. ¿Cuál es la salida de fmt.Println(1 << 10)?
Por qué:
Las operaciones bit a bit son comunes en la programación de bajo nivel.
Qué:
- 1 << 10 desplaza 1 a la izquierda por 10 bits, lo que da como resultado 1024 (2^10).
Cómo:
fmt.Println(1 << 10) // 1024
Caso de uso en la vida real:
Definición de tamaños de memoria (por ejemplo, 1 KiB = 1024 bytes).
19. ¿Cómo se declara una variable global en un paquete?
Por qué:
Las variables globales persisten durante las llamadas de función, pero pueden introducir dependencias ocultas.
Qué:
- Se declarar a nivel de paquete usando var.
Cómo:
package main
var counter int // variable global
func increment() {
counter++
}
Caso de uso en la vida real:
Seguimiento del estado de la aplicación, como los contadores de solicitudes en un servidor web.
20. ¿Cual es el valor cero de un tipo función?
Por qué:
Los tipos funciones en Go pueden ser nulos, lo que resulta útil para los patrones de devolución de llamada.
Qué:
- El valor cero es nil.
Cómo:
var f func(int) int // f == nil
if f != nil {
f(5) // safeguard
}
Caso de uso en la vida real:
Funciones de devolución de llamada opcionales en librerías (por ejemplo, logging hooks)
21. ¿Cómo se escribe un bucle for sin ninguna condición?
Por qué:
Los bucles infinitos son útiles para procesos de larga ejecución (por ejemplo, servidores).
Qué:
- Usar for {} sin condición. Salir con "break" o "return".
Cómo:
for {
// correr siempre
if condition {
break
}
}
Caso de uso en la vida real:
Ejecutar un servidor TCP que escucha conexiones hasta que se detiene manualmente.
22. ¿Cuál es la diferencia entre const y var?
Por qué:
Las constantes refuerzan la inmutabilidad, mejorando la seguridad y el rendimiento.
Qué:
- const: Valor fijo (debe poder determinarse en tiempo de compilación).
- var: Mutable, inicializado en tiempo de ejecución.
Cómo:
const PI = 3.14
var radius = 5.0
Caso de uso en la vida real:
Usando const para constantes matemáticas como π o flags de configuración.
23. ¿Cómo se declara una variable de tipo complex128?
Por qué:
Los números complejos son esenciales para los cálculos científicos y de ingeniería.
Qué:
- Utilizar la función complex() o la sintaxis literal.
Cómo:
c1 := complex(3, 4) // 3 + 4i
c2 := 5 + 7i // literal corta
Caso de uso en la vida real:
Procesamiento de señales (por ejemplo, transformadas de Fourier).
24. ¿Cuál es la salida de len("日本語")?
Por qué:
Los string en Go están codificadas en UTF-8, por lo que len() cuenta bytes, no caracteres.
Qué:
- “日本語” tiene 3 caracteres Unicode pero 9 bytes.
Cómo:
fmt.Println(len("日本語")) // salida: 9
Caso de uso en la vida real:
Validar la longitud de entrada en campos de formulario multilingües.
25. ¿Cómo se escapa comilla doble en string sin formato?
Por qué:
Los strings sin formato (comillas invertidas) ignoran los caracteres de escape, por lo que el escape requiere una solución alternativa.
Qué:
- Raw strings no pueden escapar las comillas. Utilizar una cadena normal (") en su lugar.
Cómo:
s :=`I said, "Hello"`// válido (no es necesario escapar)
Caso de uso en la vida real:
Para escribir patrones de expresiones regulares o cadenas JSON sin errores de escape.
26. Explica la diferencia entre runa y byte.
Por qué:
runa maneja Unicode, mientras que byte es para datos sin procesar.
Qué:
- byte: alias de uint8 (1 byte).
- runa: alias para int32(4 bytes, representa un punto de código Unicode).
Cómo:
b := byte('A') // 65
r := rune('世') // 19990
Caso de uso en la vida real:
Procesamiento de emojis o texto no latino (por ejemplo, caracteres chinos).
27. ¿Cómo se formatea un string con argumentos nombrados?
Por qué:
Los argumentos nombrados mejoran la legibilidad en plantillas complejas.
Qué:
- Utilizar fmt.Sprintf con %[n]v para referenciar argumentos por posición.
Cómo:
name := "Jesus"
age := 33
s := fmt.Sprintf("%[1]s is %[2]d years old. %[1]s likes Go.", name, age)
// salida: "Jesus is 30 years old. Jesus likes Go."
Caso de uso en la vida real:
Generar mensajes de error fáciles de usar con variables repetidas.
28. ¿Cuál es la diferencia entre %v y %+v en fmt.Printf?
Por qué:
%+v agrega nombres de campos al imprimir estructuras, lo que ayuda a la depuración.
Qué:
- %v: Formato predeterminado.
- %+v: Incluye nombres de campos de estructura.
Cómo:
type User struct{Name string; Age int}
u := User{"Bob", 25}
fmt.Printf("%v\n", u) // {Bob 25}
fmt.Printf("%+v\n", u) // {Name:Bob Age:25}
Caso de uso en la vida real:
Registro de objetos de solicitud/respuesta de API con contexto de campo.
29. ¿Cómo se imprime la dirección de memoria de una variable?
Por qué:
Las direcciones de memoria ayudan a depurar el comportamiento del puntero u optimizar las estructuras de datos.
Qué:
- Utilizar & con el especificador de formato %p.
Cómo:
x :=42
fmt.Printf("%p", &x) // 0xc0000120a0
Caso de uso en la vida real:
Seguimiento de alias de puntero en código concurrente.
30. ¿Por qué Go usa nil en lugar de null?
Por qué:
nil es idiomático en Go y se aplica a punteros, slices, maps, etc.
Qué:
- nil representa un valor cero para los tipos de referencia.
- null no es una palabra clave en Go.
Cómo:
var s []int
if s == nil {
fmt.Println("Slice is nil")
}
Caso de uso en la vida real:
Comprobar si un map/slice se ha inicializado antes de su uso.
Flujo de control (20 preguntas)
1. ¿En qué se diferencia la instrucción switch de Go de la de C?
Por qué:
Go simplifica el switch para reducir errores (por ejemplo, omisiones accidentales).
Qué:
- No es necesario break (los casos no se descartan por defecto).
- Admite expresiones, tipos y transición (fallthrough).
Cómo:
fruit := "apple"
switch fruit {
case "banana":
fmt.Println("Yellow")
case "apple":
fmt.Println("Red") // Imprime "Red" y sale.
}
Caso de uso en la vida real:
Manejo limpio de códigos de estado HTTP sin if-else anidados.
2. Escribir un bucle for que itere sobre una cadena de caracteres Unicode.
Por qué:
Los string están codificados en UTF-8; la iteración por runa garantiza exactitud.
Qué:
- User "for range" para obtener valores de runas, no índices de bytes.
Cómo:
s :="日本語"
for index, char := range s {
fmt.Printf("%d: %c\n", index, char)
}
// salida:
// 0: 日
// 3: 本
// 6: 語
Caso de uso en la vida real:
Validar emojis o caracteres multibyte en la entrada del usuario.
3. ¿Cómo se simula un bucle while en Go?
Por qué:
Go utiliza for en todos los bucles, mejorando la consistencia.
Qué:
- Usar for con una sola condición (sin init/post).
Cómo:
count := 0
for count < 5 {
fmt.Println(count)
count++
}
Caso de uso en la vida real:
Sondear una API hasta que se cumpla una condición (por ejemplo, la finalización de una tarea).
4. ¿Cuál es la salida de "defer" en un bucle? Explicar con código.
Por qué:
La postergación (defer) en bucle puede generar un comportamiento no deseado si no se maneja con cuidado.
Qué:
- Defer retrasa la ejecución hasta que la función circundante retorna. En los bucles, las llamadas diferidas se apilan y se ejecutan en orden LIFO.
Cómo:
func main() {
for i := 0; i < 3; i++ {
defer fmt.Println(i) // difiere la pila: 2, 1, 0
}
}
// salida:
// 2
// 1
// 0
Caso de uso en la vida real:
Aplazar accidentalmente la limpieza de recursos en un bucle puede demorarla hasta después de todas las iteraciones.
5. ¿Cómo funciona goto en Go? Dar un caso de uso válido.
Por qué:
goto se utiliza rara vez, pero puede simplificar el manejo de errores en código anidado.
Qué:
- Salta a una declaración etiquetada dentro de la misma función.
Cómo:
func process() error {
if err := step1(); err != nil {
goto cleanup
}
// ...
cleanup:
fmt.Println("Limpieza de recursos")
return nil
}
Caso de uso en la vida real:
Centralizar la lógica de limpieza en funciones con múltiples rutas de error.
6. ¿Cómo se omite una iteración en un bucle usando continue?
Por qué:
continue omite iteraciones específicas sin salir del bucle.
Qué:
- Pasar a la siguiente iteración si se cumple una condición.
Cómo:
for i := 0; i < 10; i++ {
if i%2 == 0 {
continue // saltar números pares
}
fmt.Println(i)
}
Caso de uso en la vida real:
Filtrar entradas de datos no válidas durante el procesamiento por lotes.
7. Escribir el código para salir de un bucle anidado usando break con etiquetas.
Por qué:
Las etiquetas permiten salir de los bucles externos, evitando las variables de flag
Qué:
- Etiquetar el bucle exterior y utilizar la etiqueta de interrupción.
Cómo:
outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if i*j == 4 {
break outer // sale de ambos bucles
}
}
}
Caso de uso en la vida real:
Buscando en un grid 2D y deteniéndose cuando se encuentra un objetivo.
8. ¿Cómo funciona fallthrough en una sentencia switch?
Por qué:
fallthrough permite un comportamiento de fallthrough similar al del case en C si es explícitamente necesario.
Qué:
- Fuerza la ejecución para continuar con el siguiente caso.
Cómo:
n := 2
switch n {
case 2:
fmt.Println("Two")
fallthrough
case 3:
fmt.Println("Three")
}
// salida:
// Two
// Three
Caso de uso en la vida real:
Rara vez se utiliza, pero puede agrupar la lógica compartida para múltiples casos.
9. ¿Cómo se escribe un bucle infinito utilizando for?
Por qué:
Los bucles infinitos se utilizan en servidores, programadores o procesos de ejecución prolongada.
Qué:
- Usar for sin ninguna condición.
Cómo:
for{
// Correr siempre
if condition {
break
}
}
Caso de uso en la vida real:
Un trabajo en segundo plano que supervisa una cola de mensajes.
10. ¿Cuál es la diferencia entre if x {} y if x == true {}?
Por qué:
Go fomenta comprobaciones booleanas concisas.
Qué:
- if x {} es idiomático cuando x es un booleano.
- if x == true {} es redundante.
Cómo:
x := true
if x {/* preferido */}
if x == true {/* evitar */}
Caso de uso en la vida real:
Comprobación de características o condiciones sin verbosidad innecesaria.
11. ¿Cómo se manejan múltiples condiciones en una declaración if?
Por qué:
La combinación de condiciones reduce los bloques if anidados y mejora la legibilidad.
Qué:
- Utilizar operadores lógicos (&&, ||, !).
Cómo:
age := 25
ifage >= 18 && age <= 60 {
fmt.Println("Eligible to work")
}
Caso de uso en la vida real:
Validar entrada de formulario (por ejemplo, verificar la edad y el formato del correo electrónico).
12. Escribir código para demostrar la evaluación de cortocircuito en Go.
Por qué:
El cortocircuito optimiza las operaciones lógicas al omitir evaluaciones innecesarias.
Qué:
- && detiene si la primera condición es falsa.
- || detiene si la primera condición es verdadera.
Cómo:
func isEven(n int) bool {
fmt.Println("Called")
return n%2 == 0
}
if false && isEven(4) { // isEven() nunca se llama
// ...
}
Caso de uso en la vida real:
Evitar cálculos costosos cuando falla una condición previa (por ejemplo, verificar permisos antes de acceder a los datos).
13. ¿Cómo se utiliza defer dentro de un bloque condicional?
Por qué:
defer se aplica a la función circundante, no al bloque condicional.
Qué:
- La llamada diferida se ejecuta cuando sale la función, no el bloque.
Cómo:
func process(flag bool) {
if flag {
defer fmt.Println("Cleanup A")
}
defer fmt.Println("Cleanup B")
}
process(true)
// salida: Cleanup B → Cleanup A
Caso de uso en la vida real:
Limpieza de recursos condicional (por ejemplo, cerrar archivos solo si se abren).
14. ¿Qué sucede si llamas a panic() sin recover()?
Por qué:
Los panic no recuperados hacen que el programa se bloquee, lo cual es fundamental para el manejo rápido de errores.
Qué:
- El programa finaliza con un seguimiento de la pila.
Cómo:
func main(){
panic("Something went wrong")
fmt.Println("This line never runs")
}
Caso de uso en la vida real:
Fallos catastróficos (por ejemplo, pérdida irrecuperable de la conexión a la base de datos).
15. ¿Cómo se anidan las sentencias switch?
Por qué:
Los switch anidados manejan árboles de decisiones de múltiples niveles (por ejemplo, analizan datos anidados).
Qué:
- Un switch dentro de otro switch o case.
Cómo:
value := 42
switch {
case value > 0:
switch value {
case 42:
fmt.Println("The answer")
}
}
Caso de uso en la vida real:
Analizar archivos de configuración con reglas jerárquicas.
16. ¿Cómo se utiliza range para iterar sobre un mapa?
Por qué:
Iterar mapas con range es seguro pero sin orden por diseño.
Qué:
- Cada iteración devuelve un par clave-valor aleatorio.
Cómo:
m := map[string]int{"a":1, "b":2}
for key, value := range m {
fmt.Printf("%s: %d\n", key, value)
}
Caso de uso en la vida real:
Agregación de métricas almacenadas en un mapa (por ejemplo, contar endpoints de API).
17. Escribir código para iterar sobre un slice hacia atrás.
Por qué:
La iteración hacia atrás es útil para el procesamiento inverso (por ejemplo, deshacer operaciones).
Qué:
- Bucle desde len(slice)-1 hasta 0
Cómo:
s := []int{1, 2, 3}
for i := len(s)-1; i >= 0; i-- {
fmt.Println(s[i]) // 3 → 2 → 1
}
Caso de uso en la vida real:
Invertir el orden de entradas del registro para su visualización.
18. ¿Cómo se maneja panic en una función diferida?
Por qué:
Las funciones diferidas pueden interceptar y recuperarse de los panics.
Qué:
- Utilizar recover() dentro de una función diferida.
Cómo:
func safeCall() {
defer func() {
if r :=recover(); r !=nil {
fmt.Println("Recovered:",r)
}
}()
panic("Intentional panic")
}
Caso de uso en la vida real:
Apagar controladamente un servidor después de un panic en lugar de bloquearlo.
19. ¿Cómo funciona select con casos de canales múltiples?
Por qué:
select permite comunicación sin bloqueos a través de múltiples canales.
Qué:
- Ejecuta la primera operación del un canal listo (enviar/recibir).
Cómo:
ch1 := make(chan string)
ch2 := make(chan string)
go func() { ch1 <- "hello" }()
go func() { ch2 <- "world" }()
select{
case msg := <-ch1:
fmt.Println(msg)
case msg := <-ch2:
fmt.Println(msg)
}
Caso de uso en la vida real:
Implementar tiempos de espera o priorizar operaciones de canal.
20. ¿Cuál es el resultado de defer fmt.Print("A"); fmt.Print("B")?
Por qué:
defer retrasa la ejecución hasta que la función sale.
Qué:
- Las llamadas diferidas se ejecutan en orden LIFO (último en entrar, primero en salir).
Cómo:
func main() {
defer fmt.Print("A")
fmt.Print("B")
}
// salida: B A
Caso de uso en la vida real:
Registrar acciones de limpieza una vez completada la lógica principal.
Paquetes y módulos (30 preguntas)
1. ¿Cómo crear e importar un paquete local?
Por qué:
Los paquetes locales modularizan el código, mejorando la capacidad de mantenimiento y la reutilización.
Qué:
- Crear un directorio con archivos Go (por ejemplo, utils/math.go).
- Declarar el nombre del paquete (por ejemplo, paquete utils).
- Importar utilizando la ruta del módulo definida en go.mod.
Cómo:
// utils/math.go
package utils
func Add(a, b int) int {
return a + b
}
// main.go
package main
import(
"fmt"
"your-module-path/utils" // reemplazar con nombre de módulo en go.mod
)
func main() {
sum := utils.Add(3, 5)
fmt.Println(sum) // 8
}
Caso de uso en la vida real:
Dividir una base de código monolítica en componentes reutilizables (por ejemplo, autenticación, base de datos, registrador).
2. ¿Cuál es el propósito de go.mod? ¿Cómo reemplaza a GOPATH?
Por qué:
go.mod permite la gestión de dependencias teniendo en cuenta los módulos, desacoplando los proyectos de la estructura rígida de GOPATH.
Qué:
- go.mod: define la ruta del módulo, la versión de Go y las dependencias.
- GOPATH: Espacio de trabajo heredado para código Go (obsoleto en favor de los módulos).
Cómo:
// go.mod
module github.com/yourusername/project
go1.21
require (
github.com/gorilla/mux v1.8.0
)
Caso de uso en la vida real:
Trabajando en múltiples proyectos con versiones de dependencia en conflicto.
3. Explica la diferencia entre go install y go build.
Por qué:
Comprender las herramientas de compilación garantiza flujos de trabajo de desarrollo eficientes.
Qué:
- go build: Compila el código en un archivo ejecutable en el directorio actual.
- go install: Compila e instala el ejecutable en $GOPATH/bin.
Cómo:
go build main.go # crea ./main
go install main.go # se instala en $GOPATH/bin/main
Caso de uso en la vida real:
Instalación global de herramientas de línea de comandos (por ejemplo, go install github.com/your-tool@latest).
4. ¿Cómo se manejan las dependencias cíclicas en Go?
Por qué:
Las dependencias cíclicas provocan errores de compilación e indican un diseño deficiente.
Qué:
- Refactoriza el código para romper ciclos (por ejemplo, traslada la lógica compartida a un tercer paquete).
Cómo:
// Mal: pkg A importa pkg B, que a su vez importa pkg A
// Solución: Crear pkg Common con tipos/funciones compartidas.
Caso de uso en la vida real:
Separar los modelos de dominio (usuario, producto) de las capas de servicio.