J'ai deux modules dans des fichiers séparés dans la même caisse, où la caisse a été macro_rules
activée. Je souhaite utiliser les macros définies dans un module dans un autre module.
// 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?
J'ai actuellement rencontré l'erreur du compilateur " macro undefined: 'my_macro'
" ... ce qui est logique; le système de macros s'exécute avant le système de modules. Comment contourner ce problème?
module
rust
rust-macros
utilisateur
la source
la source
module::my_macro!()?
Réponses:
Macros dans la même caisse
#[macro_use] mod foo { macro_rules! bar { () => () } } bar!(); // works
Si vous souhaitez utiliser la macro dans la même caisse, le module dans lequel votre macro est définie a besoin de l'attribut
#[macro_use]
.Les macros ne peuvent être utilisées qu'après avoir été définies. Cela signifie que cela ne fonctionne pas:
bar!(); // ERROR: cannot find macro `bar!` in this scope #[macro_use] mod foo { macro_rules! bar { () => () } }
Macros dans les caisses
Pour utiliser votre
macro_rules!
macro à partir d'autres caisses, la macro elle-même a besoin de l'attribut#[macro_export]
. La caisse d'importation peut ensuite importer la macro viause crate_name::macro_name;
.Caisse
util
#[macro_export] macro_rules! foo { () => () }
Caisse
user
use util::foo; foo!();
Notez que les macros se trouvent toujours au niveau supérieur d'une caisse; donc même si
foo
c'était à l'intérieur d'unmod bar {}
, lauser
caisse devrait encore écrireuse util::foo;
et nonuse util::bar::foo;
.Avant Rust 2018, vous deviez importer une macro à partir d'autres caisses en ajoutant l'attribut
#[macro_use]
à l'extern crate util;
instruction. Cela importerait toutes les macros à partir deutil
. Alternativement,#[macro_use(cat, dog)]
pourrait être utilisé pour importer uniquement les macroscat
etdog
. Cette syntaxe ne devrait plus être nécessaire.Plus d'informations sont disponibles dans le chapitre du langage de programmation Rust sur les macros .
la source
macros
etfoo
(qui utilise une macro demacros
), et que vous les listez par ordre alphabétique dans votre lib.rs ou main.rs, foo sera chargé avant les macros et le code ne sera pas compilé.#[macro_use]
attribut doit être sur chaque module et module parent, etc. jusqu'à ce qu'il atteigne le point où vous devez l'utiliser.#[macro_use]
et il a été déclaré en premier dans lib.rs - ne fonctionnait toujours pas. La réponse de @ Ten m'a aidé et j'ai ajouté#[macro_use]
en haut de lib.rs - puis cela a fonctionné. Mais je ne suis toujours pas sûr de la meilleure pratique puisque j'ai lu ici que "Vous n'importez pas de macros d'autres modules; vous exportez la macro depuis le module de définition"Cette réponse est obsolète depuis Rust 1.1.0-stable.
Vous devez l'ajouter
#![macro_escape]
en haut demacros.rs
et l'inclure en utilisantmod macros;
comme mentionné dans le Guide des 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
Pour référence future,
$ rustc -v rustc 0.13.0-dev (2790505c1 2014-11-03 14:17:26 +0000)
la source
#[macro_export]
attribut n'est pas nécessaire ici. Il n'est nécessaire que si la macro doit être exportée vers des utilisateurs de crate externes. Si la macro n'est utilisée qu'à l'intérieur de la caisse, elle#[macro_export]
n'est pas nécessaire.something.rs
fichier utilise d'autres modules, par exemple avecmod foobar;
, et que cefoobar
module utilise les macros demacro.rs
, alors vous devez mettremod macro;
avantmod foobar;
pour que le programme se compile. Chose mineure, mais ce n'est pas une IMO évidente.L'ajout
#![macro_use]
en haut de votre fichier contenant des macros entraînera l'extraction de toutes les macros dans main.rs.Par exemple, supposons que ce fichier s'appelle node.rs:
#![macro_use] macro_rules! test { () => { println!("Nuts"); } } macro_rules! best { () => { println!("Run"); } } pub fn fun_times() { println!("Is it really?"); }
Votre main.rs ressemblerait parfois à ce qui suit:
mod node; //We're using node.rs mod toad; //Also using toad.rs fn main() { test!(); best!(); toad::a_thing(); }
Enfin, disons que vous avez un fichier appelé toad.rs qui nécessite également ces macros:
use node; //Notice this is 'use' not 'mod' pub fn a_thing() { test!(); node::fun_times(); }
Notez qu'une fois que les fichiers sont extraits dans main.rs avec
mod
, le reste de vos fichiers y a accès via leuse
mot - clé.la source
#![macro_use]
instruction est À L' INTÉRIEUR du macro-module, pas à l'extérieur. La#![...]
syntaxe correspond au fait que les attributs s'appliquent à leurs portées contenant, par exemple#![feature(...)]
(évidemment, cela n'aurait pas de sens s'il était écrit comme#[feature(...)]
; cela exigerait sémantiquement que le compilateur active certaines fonctionnalités sur des éléments spécifiques dans une crate, plutôt que sur toute la crate racine). Donc, comme l'a dit @LukeDupin, le système de modules est en désordre, mais peut-être pour une raison différente de celle à première vue.J'ai rencontré le même problème dans Rust 1.44.1, et cette solution fonctionne pour les versions ultérieures (connue pour Rust 1.7).
Disons que vous avez un nouveau projet en tant que:
Dans main.rs , vous devez annoter que vous importez des macros à partir de la source, sinon cela ne le fera pas pour vous.
#[macro_use] mod memory; mod chunk; fn main() { println!("Hello, world!"); }
Ainsi, dans memory.rs, vous pouvez définir les macros, et vous n'avez pas besoin d'annotations:
macro_rules! grow_capacity { ( $x:expr ) => { { if $x < 8 { 8 } else { $x * 2 } } }; }
Enfin, vous pouvez l'utiliser dans chunk.rs , et vous n'avez pas besoin d'inclure la macro ici, car c'est fait dans main.rs:
grow_capacity!(8);
La réponse positive a semé la confusion chez moi, avec ce document par exemple , ce serait également utile.
la source
#[macro_use] mod foo {
.#[macro_use]
dans la définition. Le compilateur ne dit pas qu'il est mal placé.