问题描述
为什么我必须明确macro_use
宏不直接由我的代码使用,而只能由我的代码依赖项使用?
Why must I explicitly macro_use
macros not directly used by my code, but only used by my codes dependencies?
下图有两种情况:
- 宏仅由我的依赖项使用
call
、do_parse
、map
、take
、error_if
parse_der_defined
(一个函数)、fold_parsers
(一个函数)、DerObject
(一个结构体)、DerObjectContent
(一个结构体)
parse_der_defined
(a function),fold_parsers
(a function),DerObject
(a struct),DerObjectContent
(a struct)
额外问题
在编码时处理这个问题的最佳工作流程是什么?只是编译器错误,添加名称,冲洗,重复?
What's the best workflow to deal with this while coding? Just compiler error, add the name, rinse, repeat?
// 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);
}
};
}
推荐答案
宏是卫生的,但它们不会从定义它们的范围内引入"事物.
Macros are hygenic, but they don't "bring in" things from the scope they are defined in.
如果您在一个 crate 中定义宏,并使用相对名称而不是绝对名称(如果宏使用 der_read_element_name
而不是 ::der_parser::der_read_element_name
),那么您需要使用 use
将这些方法引入范围.
If you define a macro in one crate, and use relative names rather than absolute ones (if the macro produces code using der_read_element_name
rather than ::der_parser::der_read_element_name
), then you are required to use use
to bring those methods into scope.
对此的解决方案是在定义宏时始终使用绝对名称,或者在宏范围内使用"它们.例如,如果您有一个打开文件的宏,您可以执行以下两项操作之一.要么导入:
The solution to this is to always use absolute names when defining macros, or to 'use' them inside the macro scope. For instance, if you have a macro which opened a file, you do one of two things. Either import:
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)
})
}
或者直接使用绝对路径:
or use absolute paths directly:
macro_rules! open {
($file:expr) => ({
::std:fs::File::open($file)
})
}
使用其他宏的宏也会发生类似的事情!如果你有两个板条箱,比如 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
在目标 crate 中不存在,则会出错.
then when someone uses crateb
with conversation!()
, it literally expands to say_hello!(); println!("goodbye");
, and this will error if say_hello
doesn't exist in the target crate.
对此的解决方案是将所有宏从 cratea
重新导出到 crateb
.您可以通过以下方式执行此操作:
The solution to this is to re-export all macros from cratea
to crateb
. You can do this with the following:
extern crate cratea;
pub use cratea::*;
这意味着任何依赖于在 crateb
上使用 #[macro_use]
的人也可以访问所有 cratea
的宏.因此,当您在 crateb
中的宏扩展为引用 cratea
中的宏时,它将起作用.
This will mean anyone who depends using #[macro_use]
on crateb
will have access to all of cratea
's macros too. So, when your macro in crateb
expands to reference a macro in cratea
, it will work.
关于工作流程,个人轶事:
On workflow, personal anecdote:
我发现 cargo check
与 cargo-watch成为我所知道的最好的工作流程.我将在终端中启动 cargo watch
,每当保存文件时,它都会开始检查并报告语法错误.
I've found cargo check
with cargo-watch to be the best workflow I know of. I'll start cargo watch
in a terminal, and whenever a file is saved it will start a check and just report syntax errors.
一旦我感到非常自信并且没有错误,我将根据项目实际运行 cargo run
和/或 cargo test
.
Once I feel pretty confident and there are no errors, I'll actually run cargo run
and/or cargo test
depending on the project.
这篇关于为什么我必须使用仅由我的依赖项使用的宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!