모듈 파일에서 매크로를 어떻게 사용합니까?


92

상자가 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'"를 쳤다 . 매크로 시스템은 모듈 시스템보다 먼저 실행됩니다. 이 문제를 어떻게 해결합니까?


Shouldn, '당신이 사용 t에module::my_macro!()?
u_mulder

2
nope (afaik 아님)-컴파일러 메시지에 따라 모듈 접두사가 무시됩니다.
사용자

답변:


131

동일한 상자 내의 매크로

#[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)]매크로 catdog. 이 구문은 더 이상 필요하지 않습니다.

더 많은 정보는 The Rust Programming Language 장에서 매크로에 관한 것 입니다.


27
"매크로는 정의 된 후에 만 ​​사용할 수 있습니다." -언급 된 다른 모든 작업을 올바르게 수행 한 경우에도 해당 오류가 발생할 수 있기 때문에 이것이 핵심입니다. 예를 들어에서 매크로를 사용하는 macros및 모듈이 있고 lib.rs 또는 main.rs에 알파벳 순서로 나열하면 foo가 매크로보다 먼저로드되고 코드가 컴파일되지 않습니다. foomacros
neverfox

7
^ 프로 팁-이것은 완전히 나를 얻었습니다
semore_1267

3
또한 내부적으로 매크로를 사용하려면 #[macro_use]속성을 사용해야하는 지점에 도달 할 때까지 모든 모듈과 상위 모듈 등에 속성이 있어야합니다.
10

이 대답은 저에게 효과가 없었습니다. 매크로를 선언 한 모듈 #[macro_use]은 lib.rs에서 처음 선언되었고 여전히 작동하지 않았습니다. #[macro_use]@Ten 의 답변이 도움이되었고 lib.rs 상단에 추가 했습니다. 하지만 여기 에서 "다른 모듈에서 매크로를 가져 오지 않고 정의 모듈에서 매크로를 내 보냅니다."라는 글을 읽었 기 때문에 모범 사례가 무엇인지 잘 모르겠습니다 .
Sorin Bolos

저는 Rust의 매크로가 모듈과 어떻게 작동하는지 항상 잊어 버립니다. 그것은 끔찍한 시스템이며 언젠가 더 나은 시스템이 있기를 바랍니다.
Hutch Moore

20

이 답변은 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)

나는 그 속성을 완전히 놓쳤습니다. 감사!
사용자

4
BTW, #[macro_export]여기서 속성은 필요하지 않습니다. 매크로를 외부 크레이트 사용자에게 내 보내야하는 경우에만 필요합니다. 매크로가 상자 내부에서만 사용되는 경우에는 #[macro_export]필요하지 않습니다.
Vladimir Matveev

1
답변 해 주셔서 감사합니다. 나는 당신의 경우 것으로, 추가 할 something.rs파일에 예를 들어 다른 모듈을 사용 mod foobar;하고,이 foobar모듈은 매크로에서 사용 macro.rs, 당신은 넣어 가지고 mod macro; 전에 mod foobar; 프로그램을 컴파일하기. 사소한 일이지만 이것은 명백한 IMO가 아닙니다.
conradkleinespel

2
(nb이 답변은 이제 구식입니다. Lukas가 제공 한 최신 답변을 수락했습니다.)
user

7

#![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();
}

mod를 사용하여 파일 을 main.rs로 가져 오면 나머지 파일은 use키워드를 통해 파일에 액세스 할 수 있습니다 .


나는 더 많은 설명을 추가했습니다. rustc 1.22.1부터 이것은 작동합니다.
Luke Dupin

확실합니까? 이 #! [macro_use] (# [macro_use] 아님)는 어디에 문서화되어 있습니까? 찾을 수 없습니다. 여기서는 작동하지 않습니다.
Markus

이것은 내가 그것을 게시했을 때 작동했습니다. Rust의 포함 시스템은 끔찍한 엉망이며 더 이상 작동하지 않을 가능성이 있습니다.
Luke Dupin

것을 @Markus 주 #![macro_use]문이 안쪽 되지 외부 매크로 모듈. #![...]가진 속성에 구문 대응은 포함 범위, 예를 들어 적용 #![feature(...)](로 작성하면 분명이 이해가되지 것 #[feature(...)], 그것은 의미 컴파일러가 상자에 특정 항목이 아닌 전체 루트 상자에 특정 기능을 사용하도록 설정하는 것이 필요). 따라서 @LukeDupin이 말했듯이 모듈 시스템은 언뜻보기와는 다른 이유로 엉망입니다.
사용자

이 답변이 어떻게 구성이 정확히 관용적이지 않은지 언급했으면 좋겠습니다 (제외로 답변이 마음에 듭니다). 관용적 형식 옆에 배치하면 매크로가 일반적인 구성과는 다른 방식으로 모듈 시스템과 상호 작용한다는 것이 고통스럽기 때문에 (비) 관용성에도 불구하고 흥미 롭습니다. 또는 적어도 강한 냄새를 풍깁니다 (@Markus가 불만을 가지고 있음을 보여준 것처럼).
사용자

2

나는 Rust 1.44.1에서 같은 문제 를 발견했고,이 솔루션은 이후 버전에서 작동합니다 (Rust 1.7에서 작동하는 것으로 알려짐).

다음과 같은 새 프로젝트가 있다고 가정합니다.

src/
    main.rs
    memory.rs
    chunk.rs

에서 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 답변 으로, 저를 위해 혼란을 야기 예에 의해이 doc , 너무 도움이 될 것입니다.


받아 들여지는 대답은 문자 그대로 첫 번째 코드 블록의 첫 번째 줄로 #[macro_use] mod foo {있습니다.
Shepmaster

1
@Shepmaster upvoted 답변은 같은 위치에 매크로와 import 문에 대한 정의가 있으므로 혼란을 일으켰습니다. 나는 #[macro_use]정의 에서 사용 하고 있었다 . 컴파일러는 그것이 잘못 배치되었다고 말하지 않습니다.
knh190

doc.rust-lang.org/book/… 을 다시 읽고 싶을 수도 있습니다 .
Shepmaster

이 답변에 감사드립니다! 나는 받아 들인 대답에도 혼란스러워서 설명을 읽을 때까지 이해할 수 없었습니다.
Prgrm.celeritas

@Shepmaster 링크하는 섹션에서 매크로 작동 방식에 대한 언급이 없습니다. 책의 다른 부분에 연결하려고 했습니까?
detly
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.