Tenho dois módulos em arquivos separados dentro da mesma caixa, onde a caixa foi macro_rules
ativada. Quero usar as macros definidas em um módulo em outro 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?
Atualmente, encontro o erro do compilador " macro undefined: 'my_macro'
" ... o que faz sentido; o sistema macro é executado antes do sistema de módulo. Como faço para contornar isso?
module
rust
rust-macros
do utilizador
fonte
fonte
module::my_macro!()?
Respostas:
Macros dentro da mesma caixa
#[macro_use] mod foo { macro_rules! bar { () => () } } bar!(); // works
Se você quiser usar a macro na mesma caixa, o módulo em que sua macro está definida precisa do atributo
#[macro_use]
.As macros só podem ser usadas depois de definidas. Isso significa que isso não funciona:
bar!(); // ERROR: cannot find macro `bar!` in this scope #[macro_use] mod foo { macro_rules! bar { () => () } }
Macros em caixas
Para usar sua
macro_rules!
macro de outras caixas, a própria macro precisa do atributo#[macro_export]
. A caixa de importação pode então importar a macro viause crate_name::macro_name;
.Caixote
util
#[macro_export] macro_rules! foo { () => () }
Caixote
user
use util::foo; foo!();
Observe que as macros sempre vivem no nível superior de uma caixa; então, mesmo
foo
que estivesse dentro de ummod bar {}
, auser
caixa ainda teria que escreveruse util::foo;
e nãouse util::bar::foo;
.Antes do Rust 2018, você tinha que importar macro de outras caixas adicionando o atributo
#[macro_use]
àextern crate util;
instrução. Isso importaria todas as macros deutil
. Como alternativa,#[macro_use(cat, dog)]
pode ser usado apenas para importar as macroscat
edog
. Esta sintaxe não deve ser mais necessária.Mais informações estão disponíveis no capítulo The Rust Programming Language sobre macros .
fonte
macros
efoo
(que usa uma macro demacros
) e os listar em ordem alfabética em seu lib.rs ou main.rs, foo será carregado antes das macros e o código não será compilado.#[macro_use]
atributo deve estar em cada módulo e módulo pai, etc. até atingir o ponto em que você precisa usá-lo.#[macro_use]
e foi declarado primeiro em lib.rs - ainda não funcionou. A resposta do @ Ten ajudou e acrescentei#[macro_use]
ao topo do lib.rs - então funcionou. Mas ainda não tenho certeza de qual é a prática recomendada, já que li aqui que "Você não importa macros de outros módulos; você exporta a macro do módulo de definição"Esta resposta está desatualizada no Rust 1.1.0-stable.
Você precisa adicionar
#![macro_escape]
no topomacros.rs
e incluí-lo usandomod macros;
conforme mencionado no Guia 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 referência futura,
$ rustc -v rustc 0.13.0-dev (2790505c1 2014-11-03 14:17:26 +0000)
fonte
#[macro_export]
atributo é desnecessário aqui. É necessário apenas se a macro for exportada para usuários externos da caixa. Se a macro for usada apenas dentro da caixa,#[macro_export]
não é necessária.something.rs
arquivo usa outros módulos, por exemplo commod foobar;
, e estefoobar
módulo usa as macros demacro.rs
, então você deve colocarmod macro;
antesmod foobar;
para que o programa compile. Coisa menor, mas esta não é uma IMO óbvia.Adicionar
#![macro_use]
ao início do arquivo que contém macros fará com que todas as macros sejam puxadas para main.rs.Por exemplo, vamos supor que este arquivo se chame node.rs:
#![macro_use] macro_rules! test { () => { println!("Nuts"); } } macro_rules! best { () => { println!("Run"); } } pub fn fun_times() { println!("Is it really?"); }
Em algum momento, seu main.rs se pareceria com o seguinte:
mod node; //We're using node.rs mod toad; //Also using toad.rs fn main() { test!(); best!(); toad::a_thing(); }
Finalmente, digamos que você tenha um arquivo chamado toad.rs que também requer estas macros:
use node; //Notice this is 'use' not 'mod' pub fn a_thing() { test!(); node::fun_times(); }
Observe que, uma vez que os arquivos são puxados para main.rs com
mod
, o restante dos seus arquivos tem acesso a eles por meio dause
palavra - chave.fonte
#![macro_use]
instrução está DENTRO do macro-módulo, não fora. A#![...]
sintaxe corresponde a ter atributos aplicados aos escopos que os contêm, por exemplo#![feature(...)]
(obviamente, isso não faria sentido se escrito como#[feature(...)]
; semanticamente exigiria que o compilador habilitasse certos recursos em itens específicos em uma caixa, ao invés de toda a caixa raiz). Então, como @LukeDupin disse, o sistema de módulos está uma bagunça, embora talvez por um motivo diferente do que à primeira vista.Eu me deparei com o mesmo problema no Rust 1.44.1, e esta solução funciona para versões posteriores (funcionamento conhecido para o Rust 1.7).
Digamos que você tenha um novo projeto como:
Em main.rs , você precisa anotar que está importando macros da fonte, caso contrário, não servirá para você.
#[macro_use] mod memory; mod chunk; fn main() { println!("Hello, world!"); }
Portanto, em memory.rs você pode definir as macros e não precisa de anotações:
macro_rules! grow_capacity { ( $x:expr ) => { { if $x < 8 { 8 } else { $x * 2 } } }; }
Por fim, você pode usá-lo em chunk.rs e não precisa incluir a macro aqui, porque é feito em main.rs:
grow_capacity!(8);
A resposta votada causou confusão para mim, com este documento por exemplo , seria útil também.
fonte
#[macro_use] mod foo {
.#[macro_use]
em definição. O compilador não diz que está fora do lugar.mod
nosmain.rs
. Se você tiver feito issomod chunk; mod memory;
, a chamada da macromemory.rs
falhará.