У меня есть два модуля в отдельных файлах в одном ящике, в котором ящик был macro_rules
включен. Я хочу использовать макросы, определенные в одном модуле, в другом модуле.
// 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?
В настоящее время я обнаружил ошибку компилятора " macro undefined: 'my_macro'
" ... что имеет смысл; макросистема запускается перед модульной системой. Как мне обойти это?
module
rust
rust-macros
пользователь
источник
источник
module::my_macro!()?
Ответы:
Макросы в одном ящике
#[macro_use] mod foo { macro_rules! bar { () => () } } bar!(); // works
Если вы хотите использовать макрос в том же ящике, модуль, в котором определен ваш макрос, нуждается в атрибуте
#[macro_use]
.Макросы можно использовать только после того, как они были определены. Это означает, что это не работает:
bar!(); // ERROR: cannot find macro `bar!` in this scope #[macro_use] mod foo { macro_rules! bar { () => () } }
Макросы в ящиках
Чтобы использовать
macro_rules!
макрос из других ящиков, самому макросу нужен атрибут#[macro_export]
. Импортирующий ящик может затем импортировать макрос черезuse crate_name::macro_name;
.Ящик
util
#[macro_export] macro_rules! foo { () => () }
Ящик
user
use util::foo; foo!();
Обратите внимание, что макросы всегда находятся на верхнем уровне ящика; так что даже если
foo
бы был внутриmod bar {}
,user
ящик все равно пришлось бы писать,use util::foo;
а неuse util::bar::foo;
.До Rust 2018 вам приходилось импортировать макрос из других ящиков, добавляя атрибут
#[macro_use]
вextern crate util;
оператор. Это импортирует все макросы изutil
. В качестве альтернативы#[macro_use(cat, dog)]
можно использовать только для импорта макросовcat
иdog
. В этом синтаксисе больше нет необходимости.Дополнительная информация доступна в главе о макросах языка программирования Rust .
источник
macros
иfoo
(который использует макрос изmacros
), и вы перечисляете их в алфавитном порядке в ваших lib.rs или main.rs, foo будет загружен перед макросами, и код не будет компилироваться.#[macro_use]
атрибут должен быть в каждом модуле, родительском модуле и т. Д. До тех пор, пока он не достигнет точки, в которой вам нужно его использовать.#[macro_use]
был объявлен первым в lib.rs - по-прежнему не работал. Ответ @ Ten помог, и я добавил#[macro_use]
в начало lib.rs - тогда это сработало. Но я все еще не уверен, что лучше всего, так как я прочитал здесь, что «Вы не импортируете макросы из других модулей; вы экспортируете макрос из определяющего модуля»Этот ответ устарел в версии Rust 1.1.0-stable.
Вам нужно добавить
#![macro_escape]
вверхуmacros.rs
и включить его,mod 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
Для дальнейшего использования,
$ rustc -v rustc 0.13.0-dev (2790505c1 2014-11-03 14:17:26 +0000)
источник
#[macro_export]
атрибут здесь не нужен. Это необходимо только в том случае, если макрос должен быть экспортирован для внешних пользователей ящика. Если макрос используется только внутри ящика,#[macro_export]
не нужен.something.rs
файле используются другие модули, например сmod foobar;
, и этотfoobar
модуль использует макросы изmacro.rs
, то вы должны поставитьmod macro;
раньше,mod foobar;
чтобы программа скомпилировалась. Мелочь, но это не очевидная ИМО.Добавление
#![macro_use]
макросов в начало файла приведет к тому, что все макросы будут перенесены в main.rs.Например, предположим, что этот файл называется node.rs:
#![macro_use] macro_rules! test { () => { println!("Nuts"); } } macro_rules! best { () => { println!("Run"); } } pub fn fun_times() { println!("Is it really?"); }
Ваш main.rs когда-нибудь будет выглядеть следующим образом:
mod node; //We're using node.rs mod toad; //Also using toad.rs fn main() { test!(); best!(); toad::a_thing(); }
Наконец, допустим, у вас есть файл с именем toad.rs, который также требует этих макросов:
use node; //Notice this is 'use' not 'mod' pub fn a_thing() { test!(); node::fun_times(); }
Обратите внимание, что как только файлы помещаются в main.rs с помощью
mod
, остальные ваши файлы получают к ним доступ черезuse
ключевое слово.источник
#![macro_use]
оператор находится ВНУТРИ макромодуля, а не снаружи. В#![...]
синтаксическом соответствует имеющим атрибутам применяются к их содержащим областям, например ,#![feature(...)]
(очевидно , это не имело бы смысл , если записать в виде#[feature(...)]
, было бы семантический требуют, чтобы компилятор включить определенные функции по конкретным вопросам в клети, а не вся корневой обрешетке). Итак, как сказал @LukeDupin, модульная система - беспорядок, хотя, возможно, по другой причине, чем на первый взгляд.Я столкнулся с той же проблемой в Rust 1.44.1, и это решение работает для более поздних версий (известно, что оно работает в Rust 1.7).
Допустим, у вас есть новый проект:
В main.rs вам нужно отметить , что вы импортируете макросы из источника, иначе это вам не поможет.
#[macro_use] mod memory; mod chunk; fn main() { println!("Hello, world!"); }
Итак, в memory.rs вы можете определять макросы, и вам не нужны аннотации:
macro_rules! grow_capacity { ( $x:expr ) => { { if $x < 8 { 8 } else { $x * 2 } } }; }
Наконец, вы можете использовать его в chunk.rs , и вам не нужно включать макрос сюда, потому что это делается в main.rs:
grow_capacity!(8);
Upvoted ответ вызвал замешательство у меня с этим документом на примере , было бы полезно тоже.
источник
#[macro_use] mod foo {
.#[macro_use]
определение. Компилятор не говорит, что это неуместно.