web-dev-qa-db-fra.com

Comment utiliser une macro sur des fichiers de module?

J'ai deux modules dans des fichiers séparés dans la même caisse, où la caisse a macro_rules activée. Je veux 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?

Je frappe actuellement 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 cela?

50
user

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 qu'elles ont é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 sur les caisses

Pour utiliser votre macro macro_rules! À partir d'autres caisses, la macro elle-même a besoin de l'attribut #[macro_export]. La caisse d'importation peut alors importer la macro via use crate_name::macro_name;.

// --- Crate `util` ---
#[macro_export]
macro_rules! foo {
    () => ()
}


// --- Crate `user` ---
use util::foo;

foo!();

Remarque : les macros vivent toujours au niveau supérieur d'une caisse; donc même si foo serait à l'intérieur d'un mod bar {}, la caisse user devrait quand même écrire use util::foo; et pasuse util::bar::foo;.

(Avant Rust 2018, vous deviez importer une macro à partir d'autres caisses en ajoutant l'attribut #[macro_use] À l'instruction extern crate util;. Cela importerait toutes les macros de util. Alternativement, #[macro_use(cat, dog)] pourrait être utilisé pour importer uniquement les macros cat et dog. Cette syntaxe ne devrait plus être nécessaire.)


Plus d'informations sont disponibles dans The Rust Programming Language .

78
Lukas Kalbertodt

Cette réponse est obsolète depuis Rust 1.1.0-stable.


Vous devez ajouter #![macro_escape] Au sommet de macros.rs et l'inclure à l'aide de mod 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)
15
Dogbert

Ajouter #![macro_use] en haut de votre fichier contenant des macros provoquera 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 à ceci:

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 les fichiers extraits dans main.rs avec mod, les autres fichiers y ont accès via le mot clé use.

1
Luke Dupin