macro_use
コードで直接使用されず、コードの依存関係でのみマクロを明示的に使用する必要があるのはなぜですか?
以下に示す2つのケースがあります。
call
、do_parse
、map
、take
、error_if
parse_der_defined
(関数)、fold_parsers
(関数)、DerObject
(構造体)、DerObjectContent
(構造体)ボーナス質問
コーディング中にこれに対処するための最良のワークフローは何ですか?コンパイラエラー、名前の追加、すすぎ、繰り返し?
// Why is this necessary? My code does not directly use macros from this scope.
#[macro_use(call, do_parse, map, take)]
extern crate nom;
// Why is this necessary? My code does not directly use macros from this scope.
#[macro_use(error_if)]
extern crate rusticata_macros;
// Why is this necessary? My code does not directly use macros from this scope.
#[macro_use(parse_der_sequence_defined, parse_der_defined, fold_parsers)]
extern crate der_parser;
// My code does not directly use these names. Why do I need to `use` them?
use der_parser::{der_read_element_header, DerObjectContent};
// Why is this necessary? My code does not directly use these names.
use nom::{Err, ErrorKind};
// I actually use these
use nom::IResult;
use der_parser::DerObject;
fn seq_of_integers(input: &[u8]) -> IResult<&[u8], DerObject> {
parse_der_sequence_defined!(input, der_parser::parse_der_integer)
}
fn main() {
let input = [
0x30, // ASN.1 sequence
0x03, // length 3 bytes
0x02, // ASN.1 Integer
0x01, // length 1 byte
0x07, // 7
];
let der_result = seq_of_integers(&input);
match der_result {
IResult::Done(_unparsed_suffix, der) => {
assert_eq!(_unparsed_suffix.len(), 0);
let der_objects = der.as_sequence().unwrap();
for (index, der_object) in der_objects.iter().enumerate() {
println!("{}: {}", index, der_object.content.as_u32().unwrap());
}
}
IResult::Error(error) => {
eprintln!("{}", error);
}
IResult::Incomplete(_needed) => {
eprintln!("{:?}", _needed);
}
};
}
マクロは衛生的ですが、定義されている範囲から物事を「取り込む」ことはありません。
1つのクレートでマクロを定義し、絶対名ではなく相対名を使用する場合(マクロがder_read_element_name
ではなくを使用してコードを生成する場合::der_parser::der_read_element_name
)、use
これらのメソッドをスコープに含めるためにを使用する必要があります。
これに対する解決策は、マクロを定義するときに常に絶対名を使用するか、マクロスコープ内でそれらを「使用」することです。たとえば、ファイルを開くマクロがある場合、次の2つのいずれかを実行します。インポート:
macro_rules! open {
($file:expr) => ({
// note: this has to be inside the macro expansion
// `::std` means this works anywhere, not just in
// the crate root where `std` is in scope.
use ::std::fs::File;
File::open($file)
})
}
または絶対パスを直接使用します。
macro_rules! open {
($file:expr) => ({
::std:fs::File::open($file)
})
}
他のマクロを使用するマクロでも同様のことが起こります。2つの木枠がある場合は、次のように言いますcratea
。
macro_rules! say_hello {
() => (println!("hi"))
}
とcrateb
:
#[macro_use]
extern crate cratea;
macro_rules! conversation {
() => ({
say_hello!();
println!("goodbye");
})
}
次に、誰かがで使用するcrateb
とconversation!()
、文字通りに展開され、ターゲットクレートに存在しないsay_hello!(); println!("goodbye");
場合say_hello
はエラーになります。
これに対する解決策は、すべてのマクロをからcratea
に再エクスポートすることcrateb
です。これは、次の方法で実行できます。
extern crate cratea;
pub use cratea::*;
これは、に依存し#[macro_use]
ている人は誰でものcrateb
すべてcratea
のマクロにアクセスできることを意味します。したがって、のマクロをcrateb
展開してのマクロを参照するcratea
と、機能します。
ワークフローでは、個人的な逸話:
私が見つけたcargo check
と貨物時計私の知っているワークフローのベストであることを。cargo watch
ターミナルから始めます。ファイルが保存されるたびに、チェックが開始され、構文エラーが報告されます。
かなり自信があり、エラーがなくなったら、実際に実行cargo run
したりcargo test
、プロジェクトに応じて実行したりします。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加