Ich habe zwei Module in separaten Dateien in derselben Kiste, in der die Kiste macro_rules
aktiviert wurde. Ich möchte die in einem Modul definierten Makros in einem anderen Modul verwenden.
// 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?
Ich habe momentan den Compilerfehler " macro undefined: 'my_macro'
" ... getroffen, was Sinn macht; Das Makrosystem läuft vor dem Modulsystem. Wie kann ich das umgehen?
module
rust
rust-macros
Nutzer
quelle
quelle
module::my_macro!()?
Antworten:
Makros in derselben Kiste
#[macro_use] mod foo { macro_rules! bar { () => () } } bar!(); // works
Wenn Sie das Makro in derselben Kiste verwenden möchten, benötigt das Modul, in dem Ihr Makro definiert ist, das Attribut
#[macro_use]
.Makros können nur verwendet werden, nachdem sie definiert wurden. Dies bedeutet, dass dies nicht funktioniert:
bar!(); // ERROR: cannot find macro `bar!` in this scope #[macro_use] mod foo { macro_rules! bar { () => () } }
Makros über Kisten
Um Ihr
macro_rules!
Makro aus anderen Kisten zu verwenden, benötigt das Makro selbst das Attribut#[macro_export]
. Die importierende Kiste kann dann das Makro über importierenuse crate_name::macro_name;
.Kiste
util
#[macro_export] macro_rules! foo { () => () }
Kiste
user
use util::foo; foo!();
Beachten Sie, dass Makros immer auf der obersten Ebene einer Kiste leben. Selbst wenn
foo
es sich in einem befinden würdemod bar {}
,user
müsste die Kiste immer noch schreibenuse util::foo;
und nichtuse util::bar::foo;
.Vor Rust 2018 mussten Sie Makros aus anderen Kisten importieren, indem Sie das Attribut
#[macro_use]
zurextern crate util;
Anweisung hinzufügen . Das würde alle Makros von importierenutil
. Alternativ können#[macro_use(cat, dog)]
nur die Makroscat
und importiert werdendog
. Diese Syntax sollte nicht mehr erforderlich sein.Weitere Informationen finden Sie im Kapitel Die Programmiersprache Rust zu Makros .
quelle
macros
undfoo
(die ein Makro von verwendenmacros
) haben und diese in alphabetischer Reihenfolge in Ihrer lib.rs oder main.rs auflisten, wird foo vor den Makros geladen und der Code wird nicht kompiliert.#[macro_use]
Attribut für die interne Verwendung von Makros auf jedem Modul und übergeordneten Modul usw. befinden sollte, bis es den Punkt erreicht, an dem Sie es verwenden müssen.#[macro_use]
und es wurde zuerst in lib.rs deklariert - funktionierte immer noch nicht. @#[macro_use]
Tens Antwort hat geholfen und ich habe oben in lib.rs hinzugefügt - dann hat es funktioniert. Aber ich bin mir immer noch nicht sicher, was die beste Vorgehensweise ist, da ich hier gelesen habe : "Sie importieren keine Makros aus anderen Modulen; Sie exportieren das Makro aus dem definierenden Modul"Diese Antwort ist ab Rust 1.1.0-stabil veraltet.
Sie müssen hinzufügen
#![macro_escape]
an der Spitzemacros.rs
und schließen sie mit ,mod macros;
wie erwähnt in dem Macros Handbuch .$ 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
Zum späteren Nachschlagen,
$ rustc -v rustc 0.13.0-dev (2790505c1 2014-11-03 14:17:26 +0000)
quelle
#[macro_export]
Attribut hier nicht erforderlich. Es wird nur benötigt, wenn das Makro an externe Kistenbenutzer exportiert werden soll. Wenn das Makro nur in der Kiste verwendet wird,#[macro_export]
wird es nicht benötigt.something.rs
Datei andere Module verwendet, zum Beispiel mitmod foobar;
, und diesesfoobar
Modul verwendet den Makros ausmacro.rs
, dann müssen Sie setzen ,mod macro;
bevormod foobar;
für das Programm zu kompilieren. Kleinigkeit, aber das ist keine offensichtliche IMO.Wenn Sie
#![macro_use]
am Anfang Ihrer Datei Makros hinzufügen, werden alle Makros in main.rs gezogen.Angenommen, diese Datei heißt node.rs:
#![macro_use] macro_rules! test { () => { println!("Nuts"); } } macro_rules! best { () => { println!("Run"); } } pub fn fun_times() { println!("Is it really?"); }
Ihre main.rs würden irgendwann wie folgt aussehen:
mod node; //We're using node.rs mod toad; //Also using toad.rs fn main() { test!(); best!(); toad::a_thing(); }
Nehmen wir zum Schluss an, Sie haben eine Datei namens toad.rs, für die auch diese Makros erforderlich sind:
use node; //Notice this is 'use' not 'mod' pub fn a_thing() { test!(); node::fun_times(); }
Beachten Sie, dass
mod
der Rest Ihrer Dateien über dasuse
Schlüsselwort Zugriff darauf hat , sobald Dateien in main.rs mit gezogen wurden .quelle
#![macro_use]
Aussage INSIDE das Makro-Modul, nicht außerhalb. Die#![...]
Syntax entspricht der Anwendung von Attributen auf die enthaltenen Bereiche, z. B.#![feature(...)]
(dies wäre natürlich nicht sinnvoll, wenn es als geschrieben geschrieben#[feature(...)]
würde; es würde semantisch erfordern, dass der Compiler bestimmte Funktionen für bestimmte Elemente in einer Kiste aktiviert und nicht für die gesamte Stammkiste). Wie @LukeDupin sagte, ist das Modulsystem ein Chaos, wenn auch vielleicht aus einem anderen Grund als auf den ersten Blick.Ich bin in Rust 1.44.1 auf dasselbe Problem gestoßen, und diese Lösung funktioniert für spätere Versionen (bekannt für Rust 1.7).
Angenommen, Sie haben ein neues Projekt als:
In main.rs müssen Sie mit Anmerkungen versehen, dass Sie Makros aus der Quelle importieren. Andernfalls ist dies für Sie nicht ausreichend .
#[macro_use] mod memory; mod chunk; fn main() { println!("Hello, world!"); }
In memory.rs können Sie also die Makros definieren und benötigen keine Anmerkungen:
macro_rules! grow_capacity { ( $x:expr ) => { { if $x < 8 { 8 } else { $x * 2 } } }; }
Schließlich können Sie es in chunk.rs verwenden , und Sie müssen das Makro hier nicht einfügen , da es in main.rs ausgeführt wird:
grow_capacity!(8);
Die positiv bewertete Antwort hat mich verwirrt, mit diesem Dokument als Beispiel wäre es auch hilfreich.
quelle
#[macro_use] mod foo {
.#[macro_use]
in der Definition verwendet. Der Compiler sagt nicht, dass er verlegt ist.