Tengo dos módulos en archivos separados dentro de la misma caja, donde la caja se ha macro_rules
habilitado. Quiero usar las macros definidas en un módulo en otro módulo.
// macros.rs
#[macro_export] // or not? is ineffectual for this, afaik
macro_rules! my_macro(...)
// something.rs
use macros;
// use macros::my_macro; <-- unresolved import (for obvious reasons)
my_macro!() // <-- how?
Actualmente encuentro el error del compilador " macro undefined: 'my_macro'
" ... que tiene sentido; el sistema de macros se ejecuta antes que el sistema de módulos. ¿Cómo soluciono eso?
module
rust
rust-macros
usuario
fuente
fuente
module::my_macro!()?
Respuestas:
Macros dentro de la misma caja
#[macro_use] mod foo { macro_rules! bar { () => () } } bar!(); // works
Si desea utilizar la macro en la misma caja, el módulo en el que está definida su macro necesita el atributo
#[macro_use]
.Las macros solo se pueden utilizar después de que se hayan definido. Esto significa que esto no funciona:
bar!(); // ERROR: cannot find macro `bar!` in this scope #[macro_use] mod foo { macro_rules! bar { () => () } }
Macros en cajas
Para usar su
macro_rules!
macro de otras cajas, la macro en sí necesita el atributo#[macro_export]
. La caja de importación puede importar la macro a través deuse crate_name::macro_name;
.Caja
util
#[macro_export] macro_rules! foo { () => () }
Caja
user
use util::foo; foo!();
Tenga en cuenta que las macros siempre viven en el nivel superior de una caja; así que incluso si
foo
estuviera dentro de unmod bar {}
, lauser
caja todavía tendría que escribiruse util::foo;
y nouse util::bar::foo;
.Antes de Rust 2018, tenía que importar macro de otras cajas agregando el atributo
#[macro_use]
a laextern crate util;
declaración. Eso importaría todas las macros deutil
. Alternativamente,#[macro_use(cat, dog)]
podría usarse para importar solo las macroscat
ydog
. Esta sintaxis ya no debería ser necesaria.Hay más información disponible en el capítulo sobre macros de The Rust Programming Language .
fuente
macros
yfoo
(que usa una macro demacros
), y los enumera en orden alfabético en sus lib.rs o main.rs, foo se cargará antes que las macros y el código no se compilará.#[macro_use]
atributo debe estar en cada módulo y módulo principal, etc. hasta que llegue al punto en el que necesite usarlo.#[macro_use]
y se declaró primero en lib.rs - todavía no funcionó. La respuesta de @ Ten ayudó y agregué#[macro_use]
a la parte superior de lib.rs, luego funcionó. Pero todavía no estoy seguro de cuál es la mejor práctica, ya que leí aquí que "No importa macros de otros módulos; exporta la macro desde el módulo de definición"Esta respuesta está desactualizada a partir de Rust 1.1.0-estable.
Debe agregarlo
#![macro_escape]
en la parte superiormacros.rs
e incluirlo usandomod macros;
como se menciona en la Guía de macros .$ cat macros.rs #![macro_escape] #[macro_export] macro_rules! my_macro { () => { println!("hi"); } } $ cat something.rs #![feature(macro_rules)] mod macros; fn main() { my_macro!(); } $ rustc something.rs $ ./something hi
Para futura referencia,
$ rustc -v rustc 0.13.0-dev (2790505c1 2014-11-03 14:17:26 +0000)
fuente
#[macro_export]
atributo es innecesario aquí. Solo es necesario si la macro debe exportarse a usuarios externos de cajas. Si la macro solo se usa dentro de la caja,#[macro_export]
no es necesaria.something.rs
archivo usa otros módulos, por ejemplomod foobar;
, con , y estefoobar
módulo usa las macros demacro.rs
, entonces debe ponermod macro;
antesmod foobar;
para que el programa se compile. Algo menor, pero esto no es una OMI obvia.Agregar
#![macro_use]
a la parte superior de su archivo que contiene macros hará que todas las macros se incorporen a main.rs.Por ejemplo, supongamos que este archivo se llama node.rs:
#![macro_use] macro_rules! test { () => { println!("Nuts"); } } macro_rules! best { () => { println!("Run"); } } pub fn fun_times() { println!("Is it really?"); }
Su main.rs se vería en algún momento como el siguiente:
mod node; //We're using node.rs mod toad; //Also using toad.rs fn main() { test!(); best!(); toad::a_thing(); }
Finalmente, digamos que tiene un archivo llamado toad.rs que también requiere estas macros:
use node; //Notice this is 'use' not 'mod' pub fn a_thing() { test!(); node::fun_times(); }
Tenga en cuenta que una vez que los archivos se introducen en main.rs con
mod
, el resto de sus archivos tienen acceso a ellos a través de lause
palabra clave.fuente
#![macro_use]
declaración está DENTRO del macro-módulo, no fuera. La#![...]
sintaxis corresponde a tener atributos que se aplican a los ámbitos que los contienen, por ejemplo#![feature(...)]
(obviamente, esto no tendría sentido si se escribiera como#[feature(...)]
; requeriría semánticamente que el compilador habilite ciertas características en elementos específicos en una caja, en lugar de la caja raíz completa). Entonces, como dijo @LukeDupin, el sistema de módulos es un desastre, aunque quizás por una razón diferente a la primera vista.Me encontré con el mismo problema en Rust 1.44.1, y esta solución funciona para versiones posteriores (se sabe que funciona para Rust 1.7).
Digamos que tiene un nuevo proyecto como:
En main.rs , debe anotar que está importando macros desde la fuente, de lo contrario, no funcionará.
#[macro_use] mod memory; mod chunk; fn main() { println!("Hello, world!"); }
Entonces, en memory.rs puede definir las macros y no necesita anotaciones:
macro_rules! grow_capacity { ( $x:expr ) => { { if $x < 8 { 8 } else { $x * 2 } } }; }
Finalmente, puede usarlo en chunk.rs , y no necesita incluir la macro aquí, porque está hecho en main.rs:
grow_capacity!(8);
La respuesta votada a favor me causó confusión, con este documento como ejemplo , también sería útil.
fuente
#[macro_use] mod foo {
.#[macro_use]
en definición. El compilador no dice que esté fuera de lugar.