Indice Tutorial >>
- Tutorial de Tauri - Capítulo 1: Qué es Tauri y por qué deberías aprenderlo
- Tutorial de Tauri - Capítulo 2: Configuración del Entorno de Desarrollo
- Tutorial de Tauri - Capítulo 3: Tu primera aplicación Tauri
- Tauri 2.0: Aplicaciones de Escritorio con React y Rust — Ya disponible en Amazon
- Tauri vs Electron: ¿cuál elegir para tu aplicación de escritorio en 2026?
- Tutorial de Tauri - Capítulo 4: Estructura de un proyecto Tauri
- Tutorial de Tauri - Capítulo 5: Integración con React
- Tutorial de Tauri - Capítulo 6: Rust básico para desarrolladores web
- Tutorial de Tauri - Capítulo 7: Commands - Comunicación de JavaScript a Rust
- Tutorial de Tauri - Capítulo 8: Eventos - Comunicación bidireccional
- Tutorial de Tauri - Capítulo 9: Acceso al sistema de archivos
- Tutorial de Tauri - Capítulo 10: Bases de datos con SQLite
- Tutorial de Tauri - Capítulo 11: Menús, diálogos y bandejas del sistema
- Tutorial de Tauri - Capítulo 12: Proyecto práctico - Aplicación de notas
Hasta ahora hemos trabajado solo con JavaScript y React para construir nuestra interfaz. Pero la verdadera potencia de Tauri está en el backend: funciones escritas en Rust que se ejecutan con rendimiento nativo.
En los próximos capítulos vas a escribir código Rust, así que antes necesitas conocer sus bases. No te preocupes: no vamos a convertirnos en expertos. Solo aprenderemos lo justo para entender el código que escribiremos. Y si vienes de JavaScript, verás que muchos conceptos te resultan familiares, solo cambia la sintaxis.
Variables y tipos
En Rust, las variables son inmutables por defecto:
// Inmutable - no puedes cambiar el valor
let nombre = "Eduardo";
// Mutable - puedes cambiarlo
let mut contador = 0;
contador = 1;
// Con tipo explícito
let edad: u32 = 30;
let precio: f64 = 19.99;
let activo: bool = true;
Comparación con JavaScript:
| JavaScript | Rust |
|---|---|
| const x = 5 | let x = 5 |
| let x = 5 | let mut x = 5 |
| number | i32, i64, f32, f64 |
| string | String, &str |
| boolean | bool |
Tipos numéricos
A diferencia de JavaScript que solo tiene number, Rust distingue tipos:
// Enteros con signo (pueden ser negativos)
let a: i32 = -42; // 32 bits
let b: i64 = -100; // 64 bits
// Enteros sin signo (solo positivos)
let c: u32 = 42;
let d: u64 = 100;
// Decimales
let e: f64 = 3.14159; // Recomendado
Para Tauri, generalmente usarás i32 o i64 para enteros y f64 para decimales.
Strings
Rust tiene dos tipos de strings:
// &str - literal, inmutable
let saludo: &str = "Hola";
// String - dinámico, puede crecer
let mut nombre = String::from("Eduardo");
nombre.push_str(" Revilla");
En los commands de Tauri, normalmente usarás String:
#[tauri::command]
fn saludar(nombre: String) -> String {
format!("Hola, {}", nombre)
}
La macro format! es como los template literals de JavaScript.
Macros: por qué algunas funciones llevan !
En Rust verás funciones que terminan con un signo de exclamación: format!, println!, vec!. Se llaman macros.
¿Qué son? Piensa en ellas como funciones con superpoderes: pueden hacer cosas que las funciones normales no pueden, como aceptar un número variable de argumentos. El ! simplemente indica que es una macro en lugar de una función normal.
No necesitas entender cómo funcionan por dentro. Solo necesitas reconocerlas y saber usarlas. Estas son las tres que verás constantemente en Tauri:
// format! - crear un String formateado
let mensaje = format!("Hola, {}! Tienes {} años", nombre, edad);
// println! - imprimir en la consola de Rust (para depurar)
println!("El valor es: {}", variable);
// vec! - crear un vector (array)
let numeros = vec![1, 2, 3, 4, 5];
Si vienes de JavaScript, format! es el equivalente directo de los template literals:
// JavaScript
const mensaje = `Hola, ${nombre}! Tienes ${edad} años`;
// Rust
let mensaje = format!("Hola, {}! Tienes {} años", nombre, edad);
Los {} son los huecos donde se insertan los valores, en el orden en que los pasas después de la coma.
Vectores
El equivalente a los arrays de JavaScript:
// Crear vector
let frutas = vec!["manzana", "pera", "naranja"];
// Vector mutable
let mut numeros: Vec<i32> = Vec::new();
numeros.push(1);
numeros.push(2);
// Acceder
let primero = &numeros[0];
// Iterar
for num in &numeros {
println!("{}", num);
}
Estructuras
Como los objetos de JavaScript, pero con tipos:
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct Usuario {
nombre: String,
edad: u32,
email: String,
}
// Crear instancia
let usuario = Usuario {
nombre: String::from("Eduardo"),
edad: 30,
email: String::from("edu@email.com"),
};
// Acceder
println!("Nombre: {}", usuario.nombre);
Los atributos #[derive(Serialize, Deserialize)] permiten convertir a/desde JSON. Imprescindible para commands.
Option: valores que pueden no existir
En JavaScript usas null. Rust usa Option:
let nombre: Option<String> = Some(String::from("Eduardo"));
let apellido: Option<String> = None;
// Usar el valor
match nombre {
Some(n) => println!("Nombre: {}", n),
None => println!("Sin nombre"),
}
// Forma abreviada
if let Some(n) = nombre {
println!("Nombre: {}", n);
}
// Con valor por defecto
let n = apellido.unwrap_or(String::from("Desconocido"));
Result: manejo de errores
En lugar de excepciones, Rust usa Result:
fn dividir(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err(String::from("No se puede dividir por cero"))
} else {
Ok(a / b)
}
}
// Usar el resultado
match dividir(10.0, 2.0) {
Ok(resultado) => println!("Resultado: {}", resultado),
Err(error) => println!("Error: {}", error),
}
// Con el operador ?
fn calcular() -> Result<f64, String> {
let resultado = dividir(10.0, 2.0)?; // Propaga el error si falla
Ok(resultado * 2.0)
}
Match
Es como switch pero más potente:
let numero = 3;
let texto = match numero {
1 => "uno",
2 => "dos",
3 => "tres",
4 | 5 => "cuatro o cinco",
6..=10 => "entre seis y diez",
_ => "otro", // default
};
Funciones
// Función básica
fn saludar() {
println!("Hola");
}
// Con parámetros y retorno
fn sumar(a: i32, b: i32) -> i32 {
a + b // Sin punto y coma = retorno
}
// Async
async fn obtener_datos() -> String {
String::from("datos")
}
Atributos: instrucciones especiales
Verás código como #[tauri::command] o #[derive(Serialize)] encima de funciones y structs. Se llaman atributos y son instrucciones que le das al compilador.
Si has usado decoradores en Python (@app.route) o anotaciones en Java (@Override), el concepto es el mismo: modifican o añaden comportamiento al código que viene debajo.
Los que usarás en Tauri:
// Le dice a Tauri: "esta función es un command,
// hazla accesible desde JavaScript"
#[tauri::command]
fn mi_funcion() -> String {
// ...
}
// Le dice a Rust: "genera automáticamente el código
// para convertir este struct a/desde JSON"
#[derive(Serialize, Deserialize)]
struct MiEstructura {
nombre: String,
edad: u32,
}
No necesitas entender todos los detalles. Solo recuerda: los atributos #[...] configuran cómo se comporta el código que tienen debajo.
Closures
Similar a las arrow functions:
// JavaScript: (a, b) => a + b
// Rust:
let sumar = |a, b| a + b;
// Uso con iteradores
let numeros = vec![1, 2, 3];
let dobles: Vec<i32> = numeros.iter().map(|x| x * 2).collect();
Resumen
Conceptos esenciales de Rust para Tauri:
- Variables inmutables por defecto (
letvslet mut) - Tipos específicos (
i32,f64,String) - Vectores (
Vec<T>) - Estructuras con Serde
Optionpara valores opcionalesResultpara errores
format!, println!, vec!)#[...]) para configurar el comportamientoCon esto tienes suficiente Rust para entender todo lo que viene. Ahora sí, vamos a lo emocionante: conectar tu frontend JavaScript con tu backend Rust.
¿Te está gustando este tutorial?
Este tutorial forma parte del libro Tauri 2.0: Aplicaciones de Escritorio con React y Rust, disponible en Amazon en formato papel y ebook. El libro incluye todos los capítulos, tres proyectos completos paso a paso y contenido exclusivo que no encontrarás en el blog.
Un saludo, y si aún no lo has hecho no olvides suscribirte a mi blog para no perderte los próximos posts :-),También puedes seguirme en Twitter en @revi_apps y no olvides que me ayudas mucho si compartes este post en las redes sociales.
