Modül dosyalarında bir makroyu nasıl kullanabilirim?


92

Aynı sandık içinde, kasanın macro_rulesetkinleştirildiği ayrı dosyalarda iki modülüm var . Bir modülde tanımlanan makroları başka bir modülde kullanmak istiyorum.

// 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?

Şu anda " macro undefined: 'my_macro'" derleyici hatasıyla karşılaşıyorum ... bu mantıklı; makro sistemi, modül sisteminden önce çalışır. Bunun etrafında nasıl çalışırım?


Kullanmamalıydınmodule::my_macro!()?
u_mulder

2
nope (afaik değil) - modül ön ekinin ihmal edildiği bildiriliyor (derleyici mesajına göre).
kullanıcı

Yanıtlar:


131

Aynı sandık içindeki makrolar

#[macro_use]
mod foo {
    macro_rules! bar {
        () => ()
    }
}

bar!();    // works

Makroyu aynı kasada kullanmak istiyorsanız, makronuzun tanımlandığı modülün niteliğe ihtiyacı vardır #[macro_use].

Makrolar yalnızca tanımlandıktan sonra kullanılabilir . Bu, bunun çalışmadığı anlamına gelir:

bar!();  // ERROR: cannot find macro `bar!` in this scope

#[macro_use]
mod foo {
    macro_rules! bar {
        () => ()
    }
}

Kasalar arasında makrolar

macro_rules!Makronuzu diğer kasalardan kullanmak için , makronun kendisinin özniteliğe ihtiyacı vardır #[macro_export]. İçe aktarma kasası daha sonra makroyu aracılığıyla içe aktarabilir use crate_name::macro_name;.

Sandık util

#[macro_export]
macro_rules! foo {
    () => ()
}

Sandık user

use util::foo;

foo!();

Makroların her zaman bir kasanın en üst seviyesinde bulunduğunu unutmayın; Hatta eğer öyleyse foobir iç olacağını mod bar {}, usersandık hala yazma olurdu use util::foo;ve değil use util::bar::foo; .

Rust 2018 önce, özellik ekleyerek diğer sandıklardan ithalat makro zorunda #[macro_use]için extern crate util;açıklamada. Bu, tüm makroları util. Alternatif olarak, #[macro_use(cat, dog)]yalnızca makroları içe aktarmak için kullanılabilir catve dog. Bu sözdizimi artık gerekli olmamalı.

Daha fazla bilgi, makrolarla ilgili Rust Programlama Dili bölümünde mevcuttur .


27
"Makrolar yalnızca tanımlandıktan sonra kullanılabilir." - Bu anahtardır, çünkü bahsedilen diğer tüm şeyleri doğru şekilde yapmış olsanız bile bu hatayla karşılaşabilirsiniz. Örneğin, modülleriniz varsa macrosve foo(bir makroyu kullanan macros) ve bunları lib.rs veya main.rs içinde alfabetik sırayla listelerseniz, makrolardan önce foo yüklenir ve kod derlenmez.
neverfox

7
^ pro ipucu - bu tamamen beni yakaladı
semore_1267

3
Ayrıca, makroları dahili olarak kullanmak için, #[macro_use]özniteliğin kullanmanız gereken noktaya ulaşana kadar her modülde ve üst modülde vb. Olması gerektiğini unutmayın .
on

Bu cevap benim için işe yaramadı. Makronun sahip olduğunu #[macro_use]ve ilk olarak lib.rs'de açıklandığını bildiren modül - hala çalışmadı. @ Ten'in cevabı yardımcı oldu ve #[macro_use]lib.rs'nin üstüne ekledim - sonra işe yaradı. Ancak burada "Diğer modüllerden makroları içe aktarmıyorsunuz; makroyu tanımlama modülünden dışa
aktarıyorsunuz

Rust'un makrolarının modüllerle nasıl çalıştığını hep unutuyorum. Bu berbat bir sistem ve umarım bir gün daha iyi bir sistem olur.
Hutch Moore

20

Bu cevap Rust 1.1.0 kararlı olduğu için modası geçmiş durumda.


Makrolar Kılavuzu'nda belirtildiği gibi #![macro_escape]üst kısmına eklemeniz macros.rsve eklemeniz gerekir .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

Gelecekte referans olması için,

$ rustc -v
rustc 0.13.0-dev (2790505c1 2014-11-03 14:17:26 +0000)

Bu özelliği tamamen kaçırmıştım. Teşekkürler!
kullanıcı

4
BTW, #[macro_export]burada öznitelik gereksizdir. Yalnızca makronun harici kasa kullanıcılarına aktarılması gerekiyorsa gereklidir. Makro yalnızca kasanın içinde kullanılıyorsa, #[macro_export]gerekli değildir.
Vladimir Matveev

1
Cevap için çok teşekkürler. Eklemek istiyorum, eğer something.rsdosyanız başka modüller kullanıyorsa, örneğin ile mod foobar;ve bu foobarmodül de makroları kullanıyorsa , programın derlenmesi için öncesinemacro.rs koymanız gerekir . Küçük bir şey, ama bu bariz bir IMO değil. mod macro; mod foobar;
conradkleinespel

2
(Bu cevap şimdi modası geçmiş nb ben Lukas tarafından verilen yukarı güncel cevabını kabul ettik)
kullanıcıyı

7

#![macro_use]Makro içeren dosyanızın en üstüne eklemek , tüm makroların main.rs.'ye çekilmesine neden olacaktır.

Örneğin, bu dosyanın node.rs olduğunu varsayalım:

#![macro_use]

macro_rules! test {
    () => { println!("Nuts"); }
}

macro_rules! best {
    () => { println!("Run"); }
}

pub fn fun_times() {
    println!("Is it really?");
}

Main.rs'ınız bazen aşağıdaki gibi görünebilir:

mod node;  //We're using node.rs
mod toad;  //Also using toad.rs

fn main() {
    test!();
    best!();
    toad::a_thing();
}

Son olarak, şu makroları da gerektiren toad.rs adında bir dosyanız olduğunu varsayalım:

use node; //Notice this is 'use' not 'mod'

pub fn a_thing() {
  test!();

  node::fun_times();
}

Bir kez dosyalar main.rs'e çekildikten sonra mod, dosyalarınızın geri kalanının onlara useanahtar sözcük aracılığıyla eriştiğine dikkat edin .


Daha fazla açıklama ekledim. Rustc 1.22.1'den itibaren bu işe yarıyor.
Luke Dupin

Emin misiniz? Bu #! [Macro_use] (# [macro_use] değil) belgelenmiştir? Bulamıyorum Burada çalışmıyor.
Markus

Bu, yayınladığımda işe yaradı, Rust'un dahil etme sistemi o kadar berbat bir karmaşa ki, artık çalışmaması tamamen mümkün.
Luke Dupin

O @Markus Not #![macro_use]ifadesidir İÇERİ değil dışında, makro modülü. #![...]Sahip özelliklerine sözdizimi karşılık onların içeren kapsamları, örneğin uygulanır #![feature(...)](olarak yazılır eğer Açıkçası bu anlamlı olmaz #[feature(...)], aynı anlam derleyici ve kasalarda spesifik öğeler tamamı yerine kök sandık belirli özellikleri etkinleştirmek olduğunu gerektirecektir). Öyleyse, @LukeDupin'in dediği gibi, modül sistemi bir karmaşa, belki de ilk bakışta olduğundan farklı bir nedenden dolayı.
kullanıcı

Bu cevabın, yapının tam olarak deyimsel olmadığından bahsetmesini diliyorum (bu bir yana, cevabı beğendim). Diyomatik olmamasına rağmen ilginçtir çünkü onu deyimsel biçimin yanına yerleştirmek, makroların modül sistemiyle normal yapılardan farklı bir şekilde etkileşime girdiğini acı verici bir şekilde açık hale getirir. Ya da en azından güçlü bir koku yayıyor (sadece @Markus'un ona yakınmasının gösterdiği gibi).
kullanıcı

2

Ben var aynı sorun üzerinde geldi Rust 1.44.1 yılında, ve bu çözüm (Rust 1.7 için çalışan bilinir) sonraki sürümleri için çalışır.

Diyelim ki yeni bir projeniz var:

src/
    main.rs
    memory.rs
    chunk.rs

Gelen main.rs , aksi halde, bu sizin için yapmayacağım, sen kaynağından makro ithal ediyoruz o açıklama yaparak gerekir.

#[macro_use]
mod memory;
mod chunk;

fn main() {
    println!("Hello, world!");
}

Böylece memory.rs'de makroları tanımlayabilirsiniz ve ek açıklamalara ihtiyacınız yoktur:

macro_rules! grow_capacity {
    ( $x:expr ) => {
        {
            if $x < 8 { 8 } else { $x * 2 }
        }
    };
}

Son olarak chunk.rs içinde kullanabilirsiniz ve makroyu buraya eklemenize gerek yoktur, çünkü main.rs'de yapılır:

grow_capacity!(8);

Upvoted cevap ile benim için karışıklığa neden örnek, bu doküman , çok yararlı olacaktır.


Kabul cevap anlamıyla sahip olduğu ilk kod bloğunun ilk çizgiler olarak: #[macro_use] mod foo {.
Shepmaster

1
@Shepmaster, yükseltilen cevapta makroların tanımı ve aynı yerde import ifadesi var, bu yüzden kafa karışıklığına neden oldu (benim için). #[macro_use]Tanım olarak kullanıyordum . Derleyici, yanlış yerleştirildiğini söylemiyor.
knh190


Bu cevap için teşekkürler! Kabul edilen cevap beni de karıştırdı ve açıklamanızı okuyana kadar çözemedim.
Prgrm.celeritas

@Shepmaster Bağlantı verdiğiniz bölümde makroların nasıl çalıştığına dair bir şey yok. Kitabın başka bir bölümüne bağlantı vermek mi istediniz?
detly
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.