Mejores Practicas
## Objetivos de Aprendizaje
- Escribir Rust limpio e idiomático
- Seguir convenciones de nomenclatura
- Dominar el flujo de trabajo con cargo
- Aplicar pruebas efectivas
- Recordar las reglas de prestamo
## Estilo de Codigo
### Convenciones de Nomenclatura
```rust
// Modulos: snake_case
mod network_module { }
// Structs, Enums, Traits: PascalCase
struct UserAccount { }
enum Color { Red, Green, Blue }
trait Summary { }
// Funciones y Metodos: snake_case
fn calculate_total() { }
fn process_data() { }
// Variables y Parametros: snake_case
let user_name = "Alice";
fn print_message(message: &str) { }
// Constantes: SCREAMING_SNAKE_CASE
const MAX_RETRIES: u32 = 3;
const PI: f64 = 3.14159;
// Parametros de Tipo: PascalCase
fn largest(list: &[T]) -> &T { }
// Variantes de Enum: PascalCase (como structs)
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
}
```
### Formateo
```rust
// Usar rustfmt
// Ejecutar: rustfmt your_file.rs
// Longitud de linea: ~100 caracteres
// Una sentencia por linea
let name = "Alice";
let age = 30;
// Llaves
if condition {
do_something();
} else {
do_other();
}
// Brazos de match
match x {
1 => println!("one"),
2 => {
let y = 2;
println!("{}", y);
}
_ => println!("other"),
}
```
## Flujo de Trabajo con Cargo
### Nuevo Proyecto
```bash
cargo new project_name
cd project_name
cargo run
```
### Dependencias
Agregar a Cargo.toml:
```toml
[package]
name = "my_project"
version = "0.1.0"
edition = "2021"
[dependencies]
rand = "0.8" # Restriccion de version
serde = { version = "1.0", features = ["derive"] } # Con features
```
### Comandos Comunes
| Comando | Descripcion |
|---------|-------------|
| cargo build | Compilar proyecto |
| cargo run | Compilar y ejecutar |
| cargo test | Ejecutar pruebas |
| cargo doc | Generar documentacion |
| cargo check | Verificar sin compilar |
| cargo build --release | Compilacion de lanzamiento |
| cargo update | Actualizar dependencias |
### Cargo.lock
```bash
# Commit Cargo.lock para builds reproducibles
# No editarlo manualmente
cargo update -p crate_name # Actualizar un solo crate
```
## Mejores Practicas de Propiedad
### No Pelear con el Borrow Checker
```rust
// Mal: complejidad innecesaria
fn main() {
let mut data = vec![1, 2, 3];
let first = &data[0];
data.push(4); // Error: no se puede mutar mientras hay prestamo
println!("{}", first);
}
// Bien: orden apropiado
fn main() {
let mut data = vec![1, 2, 3];
println!("{}", data[0]); // Usar directamente
data.push(4); // Luego mutar
}
```
### Usar Referencias para Lectura
```rust
// Mal
fn print_sum(data: Vec) -> i32 {
let sum = data.iter().sum();
println!("{:?}", data);
sum
}
// Bien: pedir prestado
fn print_sum(data: &Vec) -> i32 {
let sum = data.iter().sum();
println!("{:?}", data);
sum
}
```
### Clone Cuando sea Necesario
```rust
// No clonar innecesariamente
fn bad_function(data: String) -> usize {
data.len()
}
fn good_function(data: &str) -> usize {
data.len()
}
// Cuando necesitas la propiedad
fn needs_owned(data: String) -> String {
// modificar data
data
}
let s = String::from("hello");
let len = needs_owned(s.clone()); // Clonar cuando sea necesario
let len = needs_owned(s); // O mover, dependiendo del uso
```
## Mejores Practicas de Manejo de Errores
### No Usar unwrap en Produccion
```rust
// Mal
fn read_config() -> Config {
Config::from_file("config.toml").unwrap()
}
// Bien: propagar error
fn read_config() -> Result {
Config::from_file("config.toml")
}
// Bien: proporcionar valor por defecto
fn read_config() -> Config {
Config::from_file("config.toml").unwrap_or_default()
}
```
### Usar expect para Pruebas
```rust
#[cfg(test)]
mod tests {
#[test]
fn test_calculation() {
assert_eq!(calculate(2, 3), 5);
}
#[test]
#[should_panic(expected = "division by zero")]
fn test_division_by_zero() {
divide(1, 0);
}
}
```
## Pruebas
### Pruebas Unitarias
```rust
fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add_positive() {
assert_eq!(add(2, 3), 5);
}
#[test]
fn test_add_negative() {
assert_eq!(add(-1, -1), -2);
}
#[test]
#[should_panic(expected = "attempt to add with overflow")]
fn test_add_overflow() {
add(i32::MAX, 1);
}
}
```
### Pruebas de Integracion
Crear pruebas en directorio tests/:
```rust
// tests/integration_test.rs
use my_crate;
#[test]
fn test_integration() {
assert_eq!(my_crate::add(1, 2), 3);
}
```
### Pruebas de Documentacion
```rust
/// Suma dos numeros.
///
/// # Ejemplos
///
/// ```
/// assert_eq!(add(2, 3), 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
```
## Documentacion
### Documentar Modulos
```rust
//! Modulo de red
//!
//! Proporciona funcionalidad para comunicacion de red.
pub mod client;
pub mod server;
```
### Documentar Funciones
```rust
/// Calcula la suma de dos numeros.
///
/// # Argumentos
///
/// * `a` - Primer numero
/// * `b` - Segundo numero
///
/// # Devuelve
///
/// La suma de a y b
///
/// # Ejemplos
///
/// ```
/// assert_eq!(add(2, 3), 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
```
### Documentar Structs y Enums
```rust
/// Representa un usuario en el sistema
pub struct User {
/// Identificador unico del usuario
pub id: u64,
/// Nombre para mostrar del usuario
pub name: String,
}
/// Representa un tipo de mensaje
pub enum Message {
/// Salir de la aplicacion
Quit,
/// Moverse a una posicion
Move { x: i32, y: i32 },
}
```
## Consejos de Rendimiento
### Evitar Asignaciones Innecesarias
```rust
// Mal: multiples asignaciones
let mut s = String::new();
for word in &words {
s.push_str(word);
s.push(' ');
}
// Bien: pre-alojar o usar join
let s = words.join(" ");
// O
let mut s = String::with_capacity(total_len);
for word in &words {
s.push_str(word);
s.push(' ');
}
```
### Usar Referencias en Bucles
```rust
// Mal: copias en cada iteracion
for word in words.clone() { }
// Bien: pedir prestado
for word in &words { }
```
### Preferir Asignacion en Pila
```rust
// Mal: asignacion en heap
let arr = Box::new([1, 2, 3]);
// Bien: asignacion en pila
let arr = [1, 2, 3];
```
## Iteradores
### Usar Iteradores en Lugar de Bucles
```rust
let numbers = vec![1, 2, 3, 4, 5];
// En lugar de
let mut sum = 0;
for n in &numbers {
sum += n;
}
// Preferir
let sum: i32 = numbers.iter().sum();
// En lugar de
let mut doubled = Vec::new();
for n in &numbers {
doubled.push(n * 2);
}
// Preferir
let doubled: Vec = numbers.iter().map(|n| n * 2).collect();
```
## Punteros Inteligentes
### Cuando Usar Box
```rust
// Tipos recursivos
enum List {
Cons(T, Box
- >),
Nil,
}
// Objetos trait
fn print_debug(item: &dyn Debug) {
println!("{:?}", item);
}
```
## Resumen
- Seguir convenciones de nomenclatura de Rust (snake_case, PascalCase)
- Usar `cargo fmt` y `clippy` para estilo
- No usar `unwrap()` en codigo de produccion
- Propagar errores con `?` o devolver Result
- Escribir pruebas: pruebas unitarias, de integracion, de documentacion
- Documentar APIs publicas
- Preferir iteradores sobre bucles cuando sea apropiado
- Clonar intencionalmente, no por accidente
- Usar `Box
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →