gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 08:14:12 25 4
gpt4 key购买 nike

为什么我必须显式macro_use 宏不直接被我的代码使用,而只被我的代码依赖项使用?

下面有2种情况:

  1. 仅由我的依赖项使用的宏
    • call, do_parse, map, take, error_if
  2. 仅由我的依赖项使用的其他范围名称
    • 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);
}
};
}

最佳答案

宏是卫生的,但它们不会从它们定义的范围内“引入”东西。

如果您在一个 crate 中定义一个宏,并使用相对名称而不是绝对名称(如果宏使用 der_read_element_name 而不是 ::der_parser::der_read_element_name 生成代码),那么您需要使用 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)
})
}

使用其他宏的宏也会发生类似的事情!如果你有两个 crate ,比如说,cratea 有:

macro_rules! say_hello {
() => (println!("hi"))
}

crateb 有:

#[macro_use]
extern crate cratea;

macro_rules! conversation {
() => ({
say_hello!();
println!("goodbye");
})
}

然后当有人将 cratebconversation!() 一起使用时,它会直接扩展为 say_hello!(); println!("goodbye");,如果 objective-c rate 中不存在 say_hello,这将出错。

解决方案是将所有宏从 cratea 重新导出到 crateb。您可以使用以下方法执行此操作:

extern crate cratea;
pub use cratea::*;

这意味着任何在 crateb 上使用 #[macro_use] 的人都可以访问所有 cratea 的宏。因此,当您在 crateb 中的宏扩展为引用 cratea 中的宏时,它将起作用。


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

我用 cargo-watch 找到了 cargo check成为我所知道的最好的工作流程。我将在终端中启动 cargo watch,无论何时保存文件,它都会开始检查并只报告语法错误。

一旦我感到非常自信并且没有错误,我就会实际运行 cargo run 和/或 cargo test,具体取决于项目。

关于rust - 为什么我必须使用仅由我的依赖项使用的宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48132095/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com