Macros procedurales: Derive y Function
Adéntrese en las macros procedurales, incluidas las macros `#[derive]` personalizadas y las macros similares a funciones, para generar código más complejo.
Macros procedurales: Derive y Function es una lección gratuita de Learn Rust Coding en CoddyKit. Esta es la lección 2 de 3. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Learn Rust Coding, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Learn Rust Coding incluye 3 lecciones en total.
Introducción a las macros procedurales
¡Bienvenido al mundo de las macros procedurales! A diferencia de las macros declarativas (macro_rules!), las macros procedurales son como funciones que operan directamente sobre código Rust.
Reciben un TokenStream como entrada, lo procesan y devuelven otro TokenStream. Esto permite generar código mucho más complejo.
Tipos de macros procedurales
Rust ofrece tres tipos principales de macros procedurales:
- Macros similares a funciones: tienen el aspecto y el comportamiento de las llamadas a funciones normales, por ejemplo,
my_macro!(...). - Macros derive: permiten implementar traits automáticamente para structs y enums mediante
#[derive(MyTrait)]. - Macros de atributos: permiten definir atributos personalizados que pueden aplicarse a elementos, por ejemplo,
#[route("/path")].
El crate `proc-macro`
Las macros procedurales deben residir en su propio tipo especial de crate. En su Cargo.toml, lo declara así:
Esto indica a Cargo que el crate contiene macros que transforman código en tiempo de compilación.
[package]
name = "my_macros"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = trueExplicación de las macros similares a funciones
Las macros similares a funciones se definen mediante el atributo #[proc_macro] aplicado a una función que recibe un proc_macro::TokenStream y devuelve otro.
Son útiles para crear DSL (lenguajes específicos de dominio) personalizados o repetir código complejo que macro_rules! no puede gestionar.
use proc_macro::TokenStream;
#[proc_macro]
pub fn my_function_macro(input: TokenStream) -> TokenStream {
// Logic to transform input TokenStream
// ...
input // For example, return the input unchanged
}Ejemplo de macro similar a una función
Aquí tiene un ejemplo conceptual. Una macro `greet_name!` que genera una instrucción de impresión. La implementación real analizaría la entrada TokenStream para extraer el nombre.
Aunque la definición de la macro es compleja, su uso es sencillo y potente:
/* In 'my_macros/src/lib.rs' */
use proc_macro::TokenStream;
#[proc_macro]
pub fn greet_name(input: TokenStream) -> TokenStream {
// Imagine parsing 'input' to get a name like 'World'
// and generating: println!("Hello, World!");
"println!(\"Hello, {}!\", \"CoddyKit\");".parse().unwrap()
}
/* In 'my_app/src/main.rs' */
use my_macros::greet_name;
fn main() {
greet_name!("CoddyKit");
}Comprender las macros `#[derive]`
Las macros derive son el tipo más común. Permiten implementar automáticamente un trait para un struct o un enum.
Cuando escribe #[derive(Debug)], una macro se ejecuta en tiempo de compilación para generar el código necesario para que su tipo implemente el trait Debug.
Implementar un `#[derive]` (concepto)
Las macros derive personalizadas suelen crearse con bibliotecas como syn (para analizar código Rust y convertirlo en un AST) y quote (para generar código Rust a partir de un AST).
Definiría una función anotada con #[proc_macro_derive(MyTrait)] que reciba un TokenStream que represente el struct o enum y devuelva la implementación generada del trait.
/* In 'my_macros/src/lib.rs' */
use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput};
use quote::quote;
#[proc_macro_derive(MyDebug)] // MyDebug is the trait name
pub fn my_debug_derive(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let name = &ast.ident;
let expanded = quote! {
impl std::fmt::Debug for #name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(stringify!(#name)).finish()
}
}
};
expanded.into()
}Ejemplo de uso de `#[derive(Debug)]`
Veamos un ejemplo práctico de una macro derive que probablemente ya haya usado: Debug. Al añadir #[derive(Debug)] a nuestro struct Point, Rust implementa automáticamente el trait Debug, lo que permite imprimir su contenido de forma clara.
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 10, y: 20 };
println!("My point is: {:?}", p);
}Macros de atributos: `#[my_attribute]`
Las macros de atributos son similares a las macros derive, pero pueden aplicarse a cualquier elemento (funciones, estructuras, módulos, etc.). Reciben como entrada el elemento al que están asociadas, además de cualquier argumento incluido entre paréntesis.
Entre sus usos habituales se incluyen el enrutamiento en frameworks web (por ejemplo, #[get("/users")]) y la configuración de pruebas (por ejemplo, #[test]).
/* In 'my_macros/src/lib.rs' */
use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn log_calls(attr: TokenStream, item: TokenStream) -> TokenStream {
// Imagine adding println! statements to 'item'
item
}
/* In 'my_app/src/main.rs' */
use my_macros::log_calls;
#[log_calls("entry_point")]
fn my_function() {
println!("Inside my_function");
}
fn main() {
my_function();
}Cuándo usar cada macro
- Macros similares a funciones: Para mini lenguajes personalizados o transformaciones complejas de bloques de código arbitrarios.
- Macros derive: Para implementar traits automáticamente en estructuras y enumeraciones.
- Macros de atributos: Para modificar o generar código alrededor de elementos específicos (funciones, estructuras) según atributos personalizados.
Cada tipo tiene un propósito único para ampliar la sintaxis y las capacidades de Rust.
Comprobación rápida: tipos de macros
¿Cuáles de las siguientes afirmaciones sobre las macros procedimentales son VERDADERAS?
Repaso: el poder de la generación de código
¡Ha explorado el avanzado mundo de las macros procedimentales!
- Hemos aprendido sobre las macros similares a funciones para crear sintaxis personalizada.
- Hemos entendido cómo las macros
#[derive]automatizan la implementación de traits. - Hemos visto brevemente las macros de atributos para generar código a nivel de elemento.
Las macros procedimentales son una herramienta potente para reducir el código repetitivo y ampliar las capacidades de Rust, lo que le permite escribir código que escribe código.
Preguntas frecuentes
¿La lección «Macros procedurales: Derive y Function» es gratis?
Sí — el texto completo de «Macros procedurales: Derive y Function» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Learn Rust Coding, actualiza a CoddyKit PRO. El curso de Learn Rust Coding incluye 3 lecciones en total.
¿Qué aprenderé en «Macros procedurales: Derive y Function»?
Adéntrese en las macros procedurales, incluidas las macros `#[derive]` personalizadas y las macros similares a funciones, para generar código más complejo. Practicas Learn Rust Coding con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Learn Rust Coding?
No se requiere experiencia previa. Learn Rust Coding en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 3.
¿Cuánto tiempo toma la lección «Macros procedurales: Derive y Function»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Learn Rust Coding?
Sí. Cada lección de Learn Rust Coding incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Macros declarativas (`macro_rules!`)
- Macros procedurales: Derive y Function
- Interacción con Rust no seguro