为什么我必须使用仅由我的依赖项使用的宏

时间:2018-01-06 21:30:06

标签: rust

为什么我必须明确macro_use宏不是我的代码直接使用的,而是仅由我的代码依赖项使用?

下面有两种情况说明:

  1. 仅由我的依赖项使用的宏
    • calldo_parsemaptakeerror_if
  2. 仅由我的依赖项使用的其他范围名称
    • parse_der_defined(函数),fold_parsers(函数),DerObject(结构),DerObjectContent(结构)
  3. 奖金问题

    编码时处理此问题的最佳工作流程是什么?只是编译错误,添加名称,冲洗,重复?

    // 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 个答案:

答案 0 :(得分:3)

宏是卫生的,但他们不会带来&#34;来自其定义范围的事物。

如果在一个包中定义宏,并使用相对名称而不是绝对名称(如果宏使用der_read_element_name而不是::der_parser::der_read_element_name生成代码),则需要使用{{1将这些方法纳入范围。

解决方法是在定义宏时始终使用绝对名称,或者使用&#39;他们在宏观范围内。例如,如果您有一个打开文件的宏,则执行以下两项操作之一。导入:

use

或直接使用绝对路径:

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) }) }

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中的宏时,它将起作用。

关于工作流程,个人轶事:

我发现crateacargo-watch成为我所知道的最佳工作流程。我将在终端中启动cargo check,每当保存文件时,它都会启动检查并报告语法错误。

一旦我感到非常自信并且没有错误,我实际上会根据项目运行cargo watch和/或cargo run