C vs Go
Hello World
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
- No hay
;al final (el compilador los pone solo). package main+func main()= tuint main().- No header files, no
#include.importtrae paquetes.
Variables y tipos
var x int = 10
y := 20 // inferencia de tipos, esto es lo más común
var nombre string = "Carlos"
const Pi = 3.14159
:= es la forma idiomática. var se usa cuando necesitas el tipo explícito o valor cero.
Funciones (retornos múltiples — esto NO existe en C)
func dividir(a, b int) (int, int) {
return a / b, a % b
}
func main() {
cociente, resto := dividir(17, 5)
fmt.Println(cociente, resto) // 3 2
}
Esto reemplaza el patrón de C de pasar punteros de salida.
Manejo de errores (no hay excepciones, ni try/catch)
func dividir(a, b int) (int, error) {
if b == 0 {
return 0, fmt.Errorf("división por cero")
}
return a / b, nil
}
func main() {
resultado, err := dividir(10, 0)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(resultado)
}
if err != nil es EL patrón en Go. Lo vas a escribir cientos de veces.
Punteros (igual que C, pero sin aritmética de punteros)
func incrementar(x *int) {
*x = *x + 1
}
func main() {
n := 5
incrementar(&n)
fmt.Println(n) // 6
}
Mismo * y &, pero no puedes hacer p++ ni p + 1. Go te protege de eso.
Structs (tu struct de C, sin typedef necesario)
type Punto struct {
X, Y int
}
func main() {
p := Punto{X: 3, Y: 4}
fmt.Println(p.X, p.Y)
}
“Métodos” en structs (no hay clases, pero hay esto)
func (p Punto) Distancia() float64 {
return math.Sqrt(float64(p.X*p.X + p.Y*p.Y))
}
func main() {
p := Punto{3, 4}
fmt.Println(p.Distancia()) // 5
}
El único loop: for
// como un for de C
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// como un while de C
i := 0
for i < 5 {
fmt.Println(i)
i++
}
// infinito
for {
break
}
Slices (tu array dinámico, como un malloc/realloc manejado por el lenguaje)
nums := []int{1, 2, 3}
nums = append(nums, 4)
fmt.Println(nums) // [1 2 3 4]
for i, v := range nums {
fmt.Println(i, v) // índice, valor
}
Concurrencia (la razón #1 por la que la gente usa Go)
func decir(msg string) {
fmt.Println(msg)
}
func main() {
go decir("en otra goroutine") // como un thread, pero ultra liviano
decir("en main")
}
Esto es como crear un pthread pero sin la ceremonia de pthread_create.
Diferencias clave respecto a C que te van a chocar al principio:
- No hay punteros nulos peligrosos sueltos por todas partes (
nilexiste pero el compilador es más estricto). - El garbage collector se encarga de la memoria — no hay
malloc/freemanual. - No hay herencia. Hay
interfaces(comportamiento, no estado). gofmtformatea tu código automáticamente, no hay debate de estilo.
Los mismos ejemplos pero en C
Dale, acá tenés los mismos ejemplos pero en C puro, para que compares directo.
Hello World
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
Variables y tipos
int x = 10;
int y = 20;
char *nombre = "Carlos";
#define PI 3.14159
En C no hay inferencia de tipos como :=, siempre tenés que declarar el tipo.
“Retornos múltiples” (en C esto se simula con punteros de salida)
void dividir(int a, int b, int *cociente, int *resto) {
*cociente = a / b;
*resto = a % b;
}
int main() {
int q, r;
dividir(17, 5, &q, &r);
printf("%d %d\n", q, r); // 3 2
}
Esto es justo lo que te mencioné: en C usás punteros para “devolver” varios valores; en Go es nativo del lenguaje.
Manejo de errores (con código de retorno + errno, o un patrón propio)
#include <errno.h>
int dividir(int a, int b, int *resultado) {
if (b == 0) {
return -1; // código de error
}
*resultado = a / b;
return 0; // éxito
}
int main() {
int resultado;
if (dividir(10, 0, &resultado) != 0) {
printf("Error: división por cero\n");
return 1;
}
printf("%d\n", resultado);
}
No hay un tipo error como en Go; en C es convención (return -1, errno, etc).
Punteros (acá sí tenés aritmética de punteros, a diferencia de Go)
void incrementar(int *x) {
*x = *x + 1;
}
int main() {
int n = 5;
incrementar(&n);
printf("%d\n", n); // 6
}
Structs (necesitás typedef para evitar escribir struct siempre)
typedef struct {
int x, y;
} Punto;
int main() {
Punto p = {.x = 3, .y = 4};
printf("%d %d\n", p.x, p.y);
}
“Métodos” en structs (en C no existen, se simulan con funciones que toman el struct)
#include <math.h>
double distancia(Punto p) {
return sqrt(p.x * p.x + p.y * p.y);
}
int main() {
Punto p = {3, 4};
printf("%f\n", distancia(p)); // 5.000000
}
C no tiene azúcar sintáctica de p.Distancia(); siempre es distancia(p).
Los loops: for y while por separado
// for
for (int i = 0; i < 5; i++) {
printf("%d\n", i);
}
// while
int i = 0;
while (i < 5) {
printf("%d\n", i);
i++;
}
// infinito
for (;;) {
break;
}
Acá está la diferencia que mencionaste al principio: C te da for Y while como cosas separadas.
“Slices” (en C: malloc + realloc manual, sin garbage collector)
#include <stdlib.h>
int main() {
int *nums = malloc(3 * sizeof(int));
nums[0] = 1; nums[1] = 2; nums[2] = 3;
// "append" manual
nums = realloc(nums, 4 * sizeof(int));
nums[3] = 4;
for (int i = 0; i < 4; i++) {
printf("%d %d\n", i, nums[i]);
}
free(nums); // tenés que liberar la memoria vos mismo
}
Concurrencia (pthreads — mucho más ceremonia que go func())
#include <pthread.h>
#include <stdio.h>
void *decir(void *msg) {
printf("%s\n", (char *)msg);
return NULL;
}
int main() {
pthread_t hilo;
pthread_create(&hilo, NULL, decir, "en otro hilo");
decir("en main");
pthread_join(hilo, NULL); // esperar que termine
}
Lo que más debería saltarte a la vista comparando ambos lados:
- En C gestionás memoria (
malloc/free) — en Go el GC lo hace por vos. - En C simulás cosas que en Go son nativas (multi-retorno, métodos).
- En C tenés
forywhileseparados — en Go es solofor. - pthreads vs goroutines: la diferencia de “ceremonia” es brutal, por eso Go es tan popular para concurrencia.