Skip to content

Commit 1f8a574

Browse files
committed
feat: reorganize summary and add enums comparison between Go and Rust
1 parent ef3143f commit 1f8a574

File tree

3 files changed

+231
-3
lines changed

3 files changed

+231
-3
lines changed

src/es/SUMMARY.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
- [Tooling](./quick-comparisons/tooling.md)
99
- [Tipos escalares](./quick-comparisons/scalar-types.md)
1010
- [Declaración de variables](./quick-comparisons/variable-declaration.md)
11-
- [Estructuras](./quick-comparisons/structures.md)
1211
- [Funciones](./quick-comparisons/functions.md)
12+
- [Estructuras](./quick-comparisons/structures.md)
13+
- [Control de flujo](./quick-comparisons/control-flow.md)
14+
- [Enums](./quick-comparisons/enums.md)
1315
- [Tuplas y Colecciones](./quick-comparisons/tuples-and-collections.md)
1416
- [Casting](./quick-comparisons/casting.md)
15-
- [Control de flujo](./quick-comparisons/control-flow.md)
1617
- [Nulabilidad y Opcionalidad](./quick-comparisons/nullability-and-optionality.md)

src/es/quick-comparisons/enums.md

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
# Enums
2+
3+
## 🐹 Enums en GO
4+
5+
En muchos lenguajes tenemos este mecanismo para definir un tipo de dato, en Go
6+
no tenemos un tipo de dato `enum` como tal, pero podemos simularlo con
7+
constantes y tipos personalizados como iota, lo cual puede estar bien para
8+
enums simples como por ejemplo:
9+
10+
```go
11+
#package main
12+
#
13+
#import "fmt"
14+
#
15+
type Estado int
16+
17+
const (
18+
Inactivo Estado = iota // 0
19+
Activo // 1
20+
Suspendido // 2
21+
Eliminado // 3
22+
)
23+
24+
func main() {
25+
estado := Activo
26+
27+
switch estado {
28+
case Inactivo:
29+
fmt.Println("El estado es: Inactivo")
30+
case Activo:
31+
fmt.Println("El estado es: Activo")
32+
case Suspendido:
33+
fmt.Println("El estado es: Suspendido")
34+
case Eliminado:
35+
fmt.Println("El estado es: Eliminado")
36+
default:
37+
fmt.Println("Estado desconocido")
38+
}
39+
}
40+
```
41+
42+
Esto funcionara pero es un caso muy básico con varios problemas, es posible que
43+
en varias oportunidades necesitemos algo más complejo, por ejemplo, si queremos
44+
no podemos simular tagged unions/sum types/tipos algebraicos, no podemos tener
45+
métodos asociados a los enums, no podemos tener un enum con un valor asociado,
46+
etc.
47+
48+
Si desearamos algo más complejo, como por ejemplo un enum con un valor asociado
49+
podríamos hacerlo de la siguiente manera:
50+
51+
```go
52+
type Mensaje interface{}
53+
54+
type Saludar struct {
55+
Nombre string
56+
}
57+
58+
type Mover struct {
59+
X, Y int
60+
}
61+
62+
type Salir struct{}
63+
64+
func procesar(m Mensaje) {
65+
switch v := m.(type) {
66+
case Saludar:
67+
fmt.Println("Hola,", v.Nombre)
68+
case Mover:
69+
fmt.Printf("Mover a (%d, %d)\n", v.X, v.Y)
70+
case Salir:
71+
fmt.Println("Adiós")
72+
default:
73+
fmt.Println("Mensaje desconocido")
74+
}
75+
}
76+
```
77+
78+
Sin embargo recurrimos a otra manera, en la que perdemos las variantes,
79+
no podemos tener un enum con un valor asociado.
80+
81+
Es por eso que en Go debemos decidir si queremos utilizar variantes simples
82+
o estructuras con interfaces para manejar casos más complejos.
83+
84+
Además como perdemos la funcionalidad de las variantes podemos generar
85+
código con errores, perdemos exhaustividad.
86+
87+
## 🦀 RUST: enum con tipos algebraicos
88+
89+
Por otro lado, los enums de Rust son reconocidos por ser especialmente potentes
90+
y versátiles, permitiendo definir variantes con datos asociados, métodos y
91+
exhaustividad en el manejo de casos.
92+
93+
En Rust definiriamos un enum de la siguiente manera:
94+
95+
```rust
96+
enum Mensaje {
97+
Saludar(String),
98+
Mover { x: i32, y: i32 },
99+
Salir,
100+
}
101+
102+
fn procesar(m: Mensaje) {
103+
match m {
104+
Mensaje::Saludar(nombre) => println!("Hola, {nombre}!"),
105+
Mensaje::Mover { x, y } => println!("Mover a ({x}, {y})"),
106+
Mensaje::Salir => println!("Adiós"),
107+
}
108+
}
109+
```
110+
111+
En este ejemplo breve estamos haciendo muchas cosas que en Go posiblemente se
112+
nos complicaria:
113+
114+
- Definimos un tipo de dato `Mensaje` el cual tiene varias variantes
115+
- La variante `Saludar` que tiene un `String` contenido
116+
- `Mover` que tiene dos campos `x` e `y` como si fuese una estructura
117+
- Y `Salir` que no tiene datos asociados
118+
- Luego tenemos una función `procesar` que recibe un `Mensaje` y utiliza
119+
`match` para manejar cada variante de forma exhaustiva.
120+
- Si no cubrimos todas las variantes lo sabremos, Rust nos pide cubrir todas las
121+
posibilidades en tiempo de compilación, lo que garantiza que no se nos olvide
122+
manejar un caso.
123+
124+
Además, podemos agregar métodos asociados a los enums, lo que nos permite
125+
encapsular la lógica relacionada con cada variante dentro del enum mismo.
126+
127+
### Representación numérica de los enums
128+
129+
En Rust, los enums pueden ser representados numéricamente, similar a como se
130+
hace en Go con `iota`, nosotros podemos definir un enum asociando un valor
131+
numérico a cada variante, incluso podemos saltar valores o definir
132+
valores específicos para cada variante.
133+
134+
```rust
135+
enum Estado {
136+
Inactivo = 0,
137+
Activo = 1,
138+
Suspendido = 2,
139+
Eliminado = 54,
140+
Desconocido = 100,
141+
}
142+
143+
fn main() {
144+
let estado = Estado::Activo;
145+
println!("El estado numérico es: {}", estado as u8); // -> 1
146+
}
147+
```
148+
149+
Sin embargo, es importante aclarar que no podemos transformar un numero a
150+
una variante de enum directamente. Esto debido a que podría resultar ambiguo.
151+
No todos los valores numéricos son válidos para los enums, es por eso que si
152+
debemos hacer esto lo ideal seria implementar un `trait` en Rust, que
153+
permita convertir un número a una variante de enum de forma segura, por supuesto
154+
esto es un poco más avanzado, lo veremos más adelante en el libro, pero para
155+
no irse con las manos vacías, aquí hay un ejemplo de cómo podríamos
156+
implementar esto:
157+
158+
```rust
159+
#[derive(Debug)]
160+
enum Estado {
161+
Inactivo = 0,
162+
Activo = 1,
163+
Suspendido = 2,
164+
Eliminado = 54,
165+
Desconocido = 100,
166+
}
167+
168+
impl From<u8> for Estado {
169+
fn from(valor: u8) -> Self {
170+
match valor {
171+
0 => Estado::Inactivo,
172+
1 => Estado::Activo,
173+
2 => Estado::Suspendido,
174+
54 => Estado::Eliminado,
175+
_ => Estado::Desconocido, // Para cualquier otro valor, usamos Desconocido
176+
}
177+
}
178+
}
179+
180+
fn main() {
181+
let estado: Estado = 1.into(); // Convertimos el número 1 a Estado::Activo
182+
println!("El estado es: {estado:?}", );
183+
}
184+
```
185+
186+
De esta manera convertimos un número a una variante de enum de forma segura,
187+
evitando ambigüedades y garantizando que solo se utilicen valores válidos.
188+
189+
### Métodos/Funciones asociadas a enums
190+
191+
En Rust, los enums pueden tener métodos asociados, lo que permite encapsular
192+
la lógica relacionada con cada variante dentro del enum mismo. Esto es útil
193+
para mantener el código organizado y evitar la repetición.
194+
195+
```rust
196+
#[derive(Debug)]
197+
enum Direccion {
198+
Norte,
199+
Sur,
200+
Este,
201+
Oeste,
202+
}
203+
204+
impl Direccion {
205+
fn girar_a_la_izquierda(&self) -> Self {
206+
match self {
207+
Direccion::Norte => Direccion::Oeste,
208+
Direccion::Oeste => Direccion::Sur,
209+
Direccion::Sur => Direccion::Este,
210+
Direccion::Este => Direccion::Norte,
211+
}
212+
}
213+
}
214+
215+
fn main() {
216+
let direccion_actual = Direccion::Norte;
217+
let nueva_direccion = direccion_actual.girar_a_la_izquierda();
218+
println!("Nueva dirección: {nueva_direccion:?}");
219+
}
220+
```
221+
222+
En este ejemplo, hemos definido un enum `Direccion` con cuatro variantes
223+
y un método `girar_a_la_izquierda` que devuelve la dirección resultante al
224+
girar a la izquierda desde la dirección actual. Esto permite que cada variante
225+
tenga su propia lógica asociada, lo que mejora la legibilidad y mantenibilidad
226+
del código.
227+

theme/pagetoc.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@media only screen and (max-width: 1280px) {
1+
@media (max-width: 1280px) {
22
.sidetoc {
33
display: none;
44
}

0 commit comments

Comments
 (0)