Rust: Programación de Sistemas Segura
Aprende Rust, el lenguaje que garantiza seguridad de memoria sin garbage collector
Rust: Programación de Sistemas Segura
Rust es un lenguaje de programación de sistemas que combina rendimiento de bajo nivel con garantías de seguridad en tiempo de compilación. Creado por Mozilla y lanzado en 2010, Rust elimina clases enteras de bugs relacionados con la memoria a través de su sistema único de ownership, sin sacrificar el rendimiento.
¿Por qué Rust? Rust ha sido votado como el “lenguaje más amado” en el Stack Overflow Survey durante 8 años consecutivos. Empresas como Microsoft, Google, Amazon y Discord usan Rust en producción.
Conceptos Fundamentales
Ownership, Borrowing y Lifetimes
El sistema de ownership es el corazón de Rust:
// Ownership - cada valor tiene un único dueño
fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1 se mueve a s2
// println!("{}", s1); // ¡ERROR! s1 ya no es válido
println!("{}", s2); // OK
}
// Borrowing - referencias inmutables
fn calcular_longitud(s: &String) -> usize {
s.len()
}
// Borrowing mutable
fn agregar_texto(s: &mut String) {
s.push_str(" world");
}
fn main() {
let mut texto = String::from("hello");
// Múltiples referencias inmutables están permitidas
let r1 = &texto;
let r2 = &texto;
println!("{} y {}", r1, r2);
// Solo UNA referencia mutable a la vez
let r3 = &mut texto;
r3.push_str("!");
println!("{}", r3);
}
// Lifetimes - garantizan que las referencias sean válidas
fn mayor<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
Tipos de Datos
// Tipos primitivos
let entero: i32 = 42;
let flotante: f64 = 3.14;
let booleano: bool = true;
let caracter: char = '🦀';
// Tuplas
let tupla: (i32, f64, &str) = (42, 3.14, "rust");
let (x, y, z) = tupla; // Destructuring
// Arrays (tamaño fijo)
let array: [i32; 5] = [1, 2, 3, 4, 5];
let primero = array[0];
// Vectores (tamaño dinámico)
let mut vec: Vec<i32> = vec![1, 2, 3];
vec.push(4);
// Strings
let s1: &str = "string literal"; // String slice
let s2: String = String::from("owned string");
// HashMap
use std::collections::HashMap;
let mut mapa: HashMap<&str, i32> = HashMap::new();
mapa.insert("clave", 42);
Structs y Enums
// Struct
#[derive(Debug, Clone)]
struct Usuario {
nombre: String,
email: String,
edad: u32,
activo: bool,
}
impl Usuario {
// Constructor
fn nuevo(nombre: String, email: String, edad: u32) -> Self {
Self {
nombre,
email,
edad,
activo: true,
}
}
// Método
fn saludar(&self) -> String {
format!("¡Hola, {}!", self.nombre)
}
// Método mutable
fn desactivar(&mut self) {
self.activo = false;
}
}
// Enum con datos
enum Mensaje {
Salir,
Mover { x: i32, y: i32 },
Escribir(String),
CambiarColor(u8, u8, u8),
}
// Pattern matching
fn procesar_mensaje(msg: Mensaje) {
match msg {
Mensaje::Salir => println!("Saliendo..."),
Mensaje::Mover { x, y } => println!("Moviendo a ({}, {})", x, y),
Mensaje::Escribir(texto) => println!("Texto: {}", texto),
Mensaje::CambiarColor(r, g, b) => println!("Color: RGB({}, {}, {})", r, g, b),
}
}
// Option y Result
fn dividir(a: f64, b: f64) -> Option<f64> {
if b == 0.0 { None } else { Some(a / b) }
}
fn leer_archivo(ruta: &str) -> Result<String, std::io::Error> {
std::fs::read_to_string(ruta)
}
Traits
// Definiendo un trait
trait Resumible {
fn resumen(&self) -> String;
// Implementación por defecto
fn descripcion(&self) -> String {
format!("Resumen: {}", self.resumen())
}
}
// Implementando trait
struct Articulo {
titulo: String,
autor: String,
contenido: String,
}
impl Resumible for Articulo {
fn resumen(&self) -> String {
format!("{} por {}", self.titulo, self.autor)
}
}
// Trait bounds en generics
fn imprimir_resumen<T: Resumible>(item: &T) {
println!("{}", item.resumen());
}
Concurrencia
use std::thread;
use std::sync::{Arc, Mutex};
// Threads básicos
fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("Thread: {}", i);
}
});
for i in 1..5 {
println!("Main: {}", i);
}
handle.join().unwrap();
}
// Compartiendo datos entre threads
fn contador_compartido() {
let contador = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let contador = Arc::clone(&contador);
let handle = thread::spawn(move || {
let mut num = contador.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Resultado: {}", *contador.lock().unwrap());
}
Herramientas del Ecosistema
| Herramienta | Propósito |
|---|---|
| cargo | Gestor de paquetes y build |
| rustfmt | Formateador de código |
| clippy | Linter con consejos avanzados |
| rust-analyzer | LSP para IDEs |
Lista de Verificación de Aprendizaje
- Entender ownership, borrowing y lifetimes
- Dominar structs, enums y pattern matching
- Aprender traits y generics
- Estudiar manejo de errores con Result y Option
- Explorar concurrencia y async/await
- Construir un proyecto CLI
- Contribuir a proyectos Rust open source
Recursos Esenciales
Cita
“Rust es un lenguaje que respeta el tiempo y la inteligencia del desarrollador.” - Steve Klabnik
¡Rust puede parecer desafiante al principio, pero las garantías de seguridad que ofrece valen la inversión!