Rust: Fundamentos para Desarrolladores con Experiencia en 2026
Aprende Rust aprovechando tu experiencia previa. Ownership, borrowing, lifetimes y patrones esenciales explicados para quienes vienen de C++, Java o Python.

Rust sigue ganando terreno entre desarrolladores profesionales, y los motivos son claros: seguridad de memoria garantizada en tiempo de compilacion, rendimiento comparable a C++ y un ecosistema moderno en constante crecimiento. Para quienes provienen de C++, Java o Python, Rust puede resultar desconcertante al principio, pero sus conceptos fundamentales se vuelven intuitivos una vez que se comprenden.
Rust ha sido el lenguaje mas querido en Stack Overflow durante 8 anos consecutivos. Adoptado por Microsoft, Google, Amazon y Meta para componentes criticos, ofrece seguridad de memoria sin necesidad de un recolector de basura.
Configuracion del Entorno de Desarrollo en Rust
Antes de escribir codigo, es necesario instalar Rust a traves de rustup, la herramienta oficial de gestion de versiones.
# install.sh
# Install Rust via rustup (macOS, Linux)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Verify installation
rustc --version
cargo --versionCargo es el gestor de paquetes y herramienta de compilacion de Rust. Combina la funcionalidad de npm, Maven y Make en una sola herramienta coherente.
# project-setup.sh
# Create a new project
cargo new my_project
cd my_project
# Generated structure:
# my_project/
# ├── Cargo.toml # Manifest (like package.json)
# └── src/
# └── main.rs # Entry point
# Essential commands
cargo build # Compile the project
cargo run # Compile and run
cargo test # Run tests
cargo check # Check without building (faster)Variables e Inmutabilidad por Defecto en Rust
Rust invierte la convencion habitual: las variables son inmutables por defecto. Este enfoque obliga a pensar explicitamente sobre la mutabilidad y previene numerosos errores.
fn main() {
// Immutable by default
let x = 5;
// x = 6; // Compile error!
// Explicitly mutable variable
let mut y = 5;
y = 6; // OK
// Shadowing: redeclaration in the same scope
let x = x + 1; // Creates a new variable x
let x = x * 2; // x is now 12
// Shadowing also allows changing the type
let spaces = " "; // &str
let spaces = spaces.len(); // usize
}El shadowing crea una nueva variable, a diferencia de mut que modifica el valor existente. El shadowing permite transformar un valor conservando un nombre claro.
Tipos de Datos Fundamentales en el Lenguaje Rust
Rust es un lenguaje con tipado estatico y excelente inferencia de tipos. A continuacion, los tipos primitivos esenciales que todo desarrollador debe conocer.
fn main() {
// Signed integers: i8, i16, i32, i64, i128, isize
let age: i32 = 30;
// Unsigned integers: u8, u16, u32, u64, u128, usize
let count: u64 = 1_000_000; // Underscores for readability
// Floats: f32, f64 (default)
let pi: f64 = 3.14159;
// Boolean
let active: bool = true;
// Unicode character (4 bytes)
let emoji: char = '🦀';
// Tuple: fixed collection of different types
let person: (String, i32) = (String::from("Alice"), 28);
let (name, age) = person; // Destructuring
// Array: fixed size, same type
let numbers: [i32; 5] = [1, 2, 3, 4, 5];
let first = numbers[0];
// Slice: view into a portion of data
let slice: &[i32] = &numbers[1..4]; // [2, 3, 4]
}Ownership: El Concepto Revolucionario de Rust
El ownership es LA innovacion de Rust. Este sistema garantiza seguridad de memoria sin recolector de basura, a cambio de una curva de aprendizaje inicial.
Las Tres Reglas del Ownership
fn main() {
// Rule 1: Each value has a single owner
let s1 = String::from("hello");
// Rule 2: When the owner goes out of scope, the value is freed
{
let s2 = String::from("world");
// s2 is valid here
}
// s2 is dropped, no longer accessible
// Rule 3: Only one ownership at a time (move)
let s3 = s1; // s1 is MOVED to s3
// println!("{}", s1); // Error: s1 is no longer valid!
println!("{}", s3); // OK: s3 is the owner
}Move vs Clone en Rust
fn main() {
// Simple types (stack): automatic Copy
let x = 5;
let y = x; // Copy, not move
println!("x = {}, y = {}", x, y); // Both are valid
// Complex types (heap): Move by default
let s1 = String::from("hello");
let s2 = s1; // Move
// s1 is no longer usable
// Explicit clone to duplicate
let s3 = String::from("world");
let s4 = s3.clone(); // Deep copy
println!("s3 = {}, s4 = {}", s3, s4); // Both valid
}Pasar un valor a una funcion transfiere el ownership. La funcion se convierte en la propietaria y el valor deja de ser accesible despues de la llamada, a menos que se retorne.
fn main() {
let s = String::from("hello");
takes_ownership(s);
// println!("{}", s); // Error: s has been moved
let x = 5;
makes_copy(x);
println!("{}", x); // OK: i32 implements Copy
// To regain ownership, return the value
let s2 = String::from("hello");
let s3 = takes_and_gives_back(s2);
println!("{}", s3); // OK
}
fn takes_ownership(s: String) {
println!("{}", s);
} // s is dropped here
fn makes_copy(x: i32) {
println!("{}", x);
}
fn takes_and_gives_back(s: String) -> String {
s // Returns ownership
}Borrowing: Referencias sin Transferencia de Propiedad
El borrowing permite utilizar un valor sin tomar el ownership. Es el mecanismo mas utilizado en Rust en la practica diaria.
fn main() {
let s1 = String::from("hello");
// Immutable reference: read-only
let len = calculate_length(&s1);
println!("Length of '{}': {}", s1, len); // s1 still valid
// Mutable reference: modification allowed
let mut s2 = String::from("hello");
change(&mut s2);
println!("{}", s2); // "hello, world"
}
fn calculate_length(s: &String) -> usize {
s.len()
} // s goes out of scope but doesn't drop (it's a reference)
fn change(s: &mut String) {
s.push_str(", world");
}Reglas del Borrowing en Rust
fn main() {
let mut s = String::from("hello");
// Rule 1: Multiple immutable references simultaneously OK
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2);
// Rule 2: ONLY ONE mutable reference at a time
let r3 = &mut s;
// let r4 = &mut s; // Error: already borrowed mutably
println!("{}", r3);
// Rule 3: No mutable ref if immutable ref exists
let r5 = &s;
// let r6 = &mut s; // Error: r5 is still active
println!("{}", r5);
// Once r5 is used for the last time, mutable borrow is allowed
let r7 = &mut s; // OK: r5 is no longer used after this
r7.push_str("!");
}¿Listo para aprobar tus entrevistas de Rust?
Practica con nuestros simuladores interactivos, flashcards y tests técnicos.
Lifetimes: Validez de Referencias en Tiempo de Compilacion
Los lifetimes aseguran que las referencias permanezcan validas. El compilador los infiere automaticamente en la mayoria de los casos, pero a veces se necesita anotacion explicita.
// Classic error: reference to freed data
// fn dangling() -> &String {
// let s = String::from("hello");
// &s // Error: s will be dropped, invalid reference!
// }
// Solution: return the owned value
fn no_dangle() -> String {
let s = String::from("hello");
s // Ownership transferred, no problem
}Anotaciones de Lifetime Explicitas
// The compiler can't figure out which reference will be returned
// fn longest(x: &str, y: &str) -> &str { ... } // Error!
// Explicit annotation: return lives as long as BOTH x AND y
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from("long string");
let result;
{
let string2 = String::from("xyz");
result = longest(&string1, &string2);
println!("Longest: {}", result); // OK here
}
// println!("{}", result); // Error: string2 dropped
}Rust aplica reglas de elision para evitar la anotacion en casos simples. Para quienes recien comienzan, basta con seguir los mensajes explicitos del compilador.
Structs e Implementaciones en Rust
Las structs son los bloques de construccion para tipos personalizados en Rust.
// Struct definition
#[derive(Debug)] // Enables printing with {:?}
struct User {
username: String,
email: String,
active: bool,
sign_in_count: u64,
}
// Implementation block for methods
impl User {
// Constructor (convention: fn new or descriptive name)
fn new(username: String, email: String) -> Self {
Self {
username,
email,
active: true,
sign_in_count: 1,
}
}
// Method: takes &self (reference to instance)
fn is_active(&self) -> bool {
self.active
}
// Method with mutation: takes &mut self
fn deactivate(&mut self) {
self.active = false;
}
// Method consuming self (rare)
fn into_username(self) -> String {
self.username
}
}
fn main() {
let mut user = User::new(
String::from("alice"),
String::from("alice@example.com"),
);
println!("Active: {}", user.is_active());
user.deactivate();
println!("Active: {}", user.is_active());
// Debug print
println!("{:?}", user);
}Enums y Pattern Matching: Tipos Algebraicos en Rust
Los enums de Rust son mucho mas potentes que en la mayoria de los lenguajes: cada variante puede contener datos asociados.
// Simple enum
enum Direction {
North,
South,
East,
West,
}
// Enum with data (algebraic data type)
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(u8, u8, u8),
}
impl Message {
fn process(&self) {
match self {
Message::Quit => println!("Quitting"),
Message::Move { x, y } => println!("Moving to ({}, {})", x, y),
Message::Write(text) => println!("Writing: {}", text),
Message::ChangeColor(r, g, b) => {
println!("Color: rgb({}, {}, {})", r, g, b)
}
}
}
}
fn main() {
let msg = Message::Move { x: 10, y: 20 };
msg.process();
let msg2 = Message::Write(String::from("Hello Rust!"));
msg2.process();
}Option y Result: Manejo de Errores sin Excepciones
use std::fs::File;
use std::io::{self, Read};
fn main() {
// Option<T>: present or absent value (replaces null)
let numbers = vec![1, 2, 3];
let first: Option<&i32> = numbers.first();
match first {
Some(n) => println!("First: {}", n),
None => println!("Empty list"),
}
// Utility methods
let value = first.unwrap_or(&0);
let doubled = first.map(|n| n * 2);
// Result<T, E>: success or error
let result = read_file("config.txt");
match result {
Ok(content) => println!("Content: {}", content),
Err(e) => println!("Error: {}", e),
}
}
fn read_file(path: &str) -> Result<String, io::Error> {
let mut file = File::open(path)?; // ? propagates the error
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(content)
}El operador ? es azucar sintactico para la propagacion de errores. Retorna automaticamente el error si el Result es Err; de lo contrario, desenvuelve el valor Ok.
Traits: Polimorfismo al Estilo de Rust
Los traits definen comportamiento compartido, similar a las interfaces de Java o los protocolos de Swift.
// Trait definition
trait Summary {
fn summarize(&self) -> String;
// Method with default implementation
fn preview(&self) -> String {
format!("{}...", &self.summarize()[..50.min(self.summarize().len())])
}
}
struct Article {
title: String,
author: String,
content: String,
}
struct Tweet {
username: String,
content: String,
}
// Implementation for Article
impl Summary for Article {
fn summarize(&self) -> String {
format!("{} by {}", self.title, self.author)
}
}
// Implementation for Tweet
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("@{}: {}", self.username, self.content)
}
}
// Function accepting any type implementing Summary
fn notify(item: &impl Summary) {
println!("Breaking news: {}", item.summarize());
}
// Equivalent syntax with trait bound
fn notify_generic<T: Summary>(item: &T) {
println!("Breaking news: {}", item.summarize());
}
fn main() {
let article = Article {
title: String::from("Rust 2026"),
author: String::from("Community"),
content: String::from("..."),
};
let tweet = Tweet {
username: String::from("rustlang"),
content: String::from("Rust is awesome!"),
};
notify(&article);
notify(&tweet);
}Colecciones Esenciales de la Biblioteca Estandar
Rust proporciona colecciones potentes en su biblioteca estandar.
use std::collections::HashMap;
fn main() {
// Vec<T>: dynamic array
let mut numbers: Vec<i32> = Vec::new();
numbers.push(1);
numbers.push(2);
numbers.push(3);
// vec! macro for initialization
let nums = vec![1, 2, 3, 4, 5];
// Iteration
for n in &nums {
println!("{}", n);
}
// Functional methods
let doubled: Vec<i32> = nums.iter().map(|x| x * 2).collect();
let sum: i32 = nums.iter().sum();
let evens: Vec<&i32> = nums.iter().filter(|x| *x % 2 == 0).collect();
// String: growable UTF-8 string
let mut s = String::from("Hello");
s.push_str(", World!");
s.push('!');
// Concatenation
let s1 = String::from("Hello, ");
let s2 = String::from("World!");
let s3 = s1 + &s2; // s1 moved, s2 borrowed
// or with format!
let s4 = format!("{}{}", "Hello, ", "World!");
// HashMap<K, V>
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Red"), 50);
// Access with get (returns Option)
if let Some(score) = scores.get("Blue") {
println!("Blue: {}", score);
}
// Entry API for conditional insertion
scores.entry(String::from("Yellow")).or_insert(25);
}Manejo Idiomatico de Errores en Rust
El manejo correcto de errores es fundamental en Rust. A continuacion se presentan los patrones recomendados.
use std::fs::File;
use std::io::{self, Read};
use std::num::ParseIntError;
// Define a custom error type
#[derive(Debug)]
enum AppError {
Io(io::Error),
Parse(ParseIntError),
Custom(String),
}
// Implement From for automatic conversion
impl From<io::Error> for AppError {
fn from(err: io::Error) -> Self {
AppError::Io(err)
}
}
impl From<ParseIntError> for AppError {
fn from(err: ParseIntError) -> Self {
AppError::Parse(err)
}
}
// Function returning Result with custom error
fn read_number_from_file(path: &str) -> Result<i32, AppError> {
let mut file = File::open(path)?; // io::Error -> AppError
let mut content = String::new();
file.read_to_string(&mut content)?;
let number: i32 = content.trim().parse()?; // ParseIntError -> AppError
Ok(number)
}
fn main() {
match read_number_from_file("number.txt") {
Ok(n) => println!("Number: {}", n),
Err(AppError::Io(e)) => println!("IO error: {}", e),
Err(AppError::Parse(e)) => println!("Parse error: {}", e),
Err(AppError::Custom(msg)) => println!("Error: {}", msg),
}
}Para proyectos reales, el crate thiserror (para bibliotecas) y anyhow (para aplicaciones) simplifican enormemente el manejo de errores.
Testing Integrado en el Lenguaje Rust
Rust integra un framework de testing directamente en el lenguaje.
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
pub fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err(String::from("Division by zero"))
} else {
Ok(a / b)
}
}
// Test module (compiled only for `cargo test`)
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
}
#[test]
fn test_add_negative() {
assert_eq!(add(-1, 1), 0);
}
#[test]
fn test_divide_success() {
assert_eq!(divide(10, 2), Ok(5));
}
#[test]
fn test_divide_by_zero() {
assert!(divide(10, 0).is_err());
}
#[test]
#[should_panic(expected = "index out of bounds")]
fn test_panic() {
let v = vec![1, 2, 3];
let _ = v[99]; // Panic!
}
}Conclusion
Rust ofrece un paradigma unico que combina seguridad de memoria y alto rendimiento. Los conceptos de ownership y borrowing resultan restrictivos al principio, pero se vuelven naturales con la practica. El compilador de Rust es un aliado invaluable: sus mensajes de error se encuentran entre los mejores de la industria.
Lista de Verificacion para Comenzar
- Instalar Rust via rustup y dominar Cargo
- Comprender la diferencia entre inmutabilidad y mutabilidad explicita
- Dominar las tres reglas del ownership
- Practicar el borrowing con referencias
&y&mut - Utilizar
OptionyResulten lugar de null y excepciones - Escribir tests con
#[test]
¡Empieza a practicar!
Pon a prueba tu conocimiento con nuestros simuladores de entrevista y tests técnicos.
La comunidad de Rust es acogedora y los recursos son abundantes. El libro oficial "The Rust Programming Language" esta disponible de forma gratuita en linea. Con estos fundamentos solidos, el camino esta abierto para explorar temas avanzados como async/await, macros y WebAssembly.
Etiquetas
Compartir
Artículos relacionados

Ownership y Borrowing en Rust: Guía Completa
Domina el sistema de ownership y borrowing de Rust. Reglas de propiedad, referencias, lifetimes y patrones avanzados de gestión de memoria.

Preguntas de Entrevista sobre Rust: Guia Completa 2026
Las 25 preguntas mas comunes en entrevistas sobre Rust. Ownership, borrowing, lifetimes, traits, async y concurrencia con respuestas detalladas y ejemplos de codigo.

Ownership y Borrowing en Rust: La Guia Definitiva para Dominarlo Todo
Ownership y borrowing en Rust explicados con codigo real. Semantica de movimiento, referencias, lifetimes y patrones del borrow checker para gestion segura de memoria en 2026.