我需要将文本文件或文本文件的内容传递给过程宏,以便过程宏在编译时根据该文本文件的内容进行操作。也就是说,文本文件配置宏的输出。其用例是定义宏构建到库中的寄存器映射的文件。
第二个要求是文本文件由 正确处理Cargo,以便对文本文件的更改触发重新编译,就像对源文件的更改触发重新编译一样。
我最初的想法是使用宏创建一个static字符串include_str!。这解决了第二个要求,但我不知道如何将其传递给宏 - 此时我只有要传入的字符串的标识符:
use my_macro_lib::my_macro;
static MYSTRING: &'static str = include_str!("myfile");
my_macro!(MYSTRING); // Not the string itself!
Run Code Online (Sandbox Code Playgroud)
我可以将一个字符串传递给宏,其中包含字符串文字中的文件名,然后在宏内打开该文件:
my_macro!("myfile");
Run Code Online (Sandbox Code Playgroud)
此时我有两个问题:
Span,但似乎一般不会(也许我错过了一些东西?)。Cargo如何使文件 make触发更改后的重新编译并不明显。我必须强制执行的一个想法是在宏的输出中添加 an include_str!("myfile"),这有望导致编译器意识到“myfile”,但这有点麻烦。有什么方法可以做我想做的事情吗?也许通过某种方式获取外部创建的宏内的字符串内容,或者可靠地获取调用 rust 文件的路径(然后Cargo正确进行处理更改)。
顺便说一句,我读过很多地方告诉我无法访问宏内变量的内容,但在我看来,这正是宏quote正在做的事情#variables。这是如何运作的?
应该如何a_proc_macro定义以便它“返回”一个 5?
fn main() {
let a = a_proc_macro!();
assert!(a == 5);
}
Run Code Online (Sandbox Code Playgroud) 使用 Rust 时处理派生宏中的辅助属性的简化方法是什么?为了说明我正在寻找的内容,我定义了一个名为 的派生宏Duplicate,它创建一个新结构,其中包含旧结构中已由辅助属性标记的所有元素。基本上就是这样转
#[derive(Duplicate)]
struct MyStruct {
#[dupe_me]
x : Vec <f64>,
y : bool,
#[dupe_me]
z : char,
}
Run Code Online (Sandbox Code Playgroud)
进入
#[derive(Debug)]
struct MyStructDuplicated {
x : Vec <f64>,
z : char,
}
Run Code Online (Sandbox Code Playgroud)
代码的结构是
./mymacro/src/lib.rs
./mymacro/Cargo.toml
./mybin/src/main.rs
./mybin/Cargo.toml
Run Code Online (Sandbox Code Playgroud)
与mymacro/Cargo.toml作为
[package]
name = "mymacro"
version = "0.1.0"
authors = ["blank"]
edition = "2018"
[lib]
proc-macro = true
[dependencies]
syn = "1.0.11"
quote = "1.0.2"
proc-macro2 = "1.0.6"
Run Code Online (Sandbox Code Playgroud)
并lib.rs作为
[package]
name = "mymacro"
version = …Run Code Online (Sandbox Code Playgroud) 我需要获取每个方法的调用者的源位置。我正在尝试创建一个proc_macro_attribute来捕获位置并打印它。
#[proc_macro_attribute]
pub fn get_location(attr: TokenStream, item: TokenStream) -> TokenStream {
// Get and print file!(), line!() of source
// Should print line no. 11
item
}
Run Code Online (Sandbox Code Playgroud)
#[get_location]
fn add(x: u32, y: u32) -> u32 {
x + y
}
fn main() {
add(1, 5); // Line No. 11
}
Run Code Online (Sandbox Code Playgroud) 我在 Rust 中发现了几个有用的宏,即:file!(), line!(), stringify!()我还发现 Rust 允许带有可变参数的宏,如下所述:
macro_rules! print_all {
($($args:expr),*) => {{
$(
println!("{}", $args);
)*
}}
}
Run Code Online (Sandbox Code Playgroud)
我的目标是以某种方式将所有这些宏合并到一个我将在故障排除/调试期间使用的宏中。trace!因此在以下示例中调用宏:
let a: i32 = 1;
let b: i32 = 2;
trace!(a,b)
Run Code Online (Sandbox Code Playgroud)
应该扩展到这样的东西:
println!("TRACE: file: {}, line: {}, a: {}, b: {}", file!(), line!(), a, b);
Run Code Online (Sandbox Code Playgroud)
是否可以?如果是,这样的宏将如何工作?
我正在尝试编写一个 Rust 宏,用重复元素填充数组,在本例中用零填充。这就是我想出的:
macro_rules! pad4 {
() => {
println!("0b00000000, 0b00000000, 0b00000000, 0b00000000");
}
}
const arr: [u8; 8] = [pad4!(), 0b01111100, 0b10000010, 0b00000010, 0b01111110];
Run Code Online (Sandbox Code Playgroud)
但我收到以下错误:
macro_rules! pad4 {
() => {
println!("0b00000000, 0b00000000, 0b00000000, 0b00000000");
}
}
const arr: [u8; 8] = [pad4!(), 0b01111100, 0b10000010, 0b00000010, 0b01111110];
Run Code Online (Sandbox Code Playgroud) 我试图理解 Rust 宏语法。在这里我读到宏通常可以通过 3 种方式调用:
mymacro!(<tokens>);
mymacro![<tokens>];
mymacro!{<tokens>};
Run Code Online (Sandbox Code Playgroud)
...然后我看到一个示例宏定义也使用宏 ( macro_rules),但语法不符合以下规则:
macro_rules! name {<tokens>}
Run Code Online (Sandbox Code Playgroud)
是name一个标记,我们在这里有第四个合法的宏调用形式,或者macro_rules是一个关键字而不仅仅是宏,并且使用常规宏不可用的特殊语法?
是否可以将macro_rules!类型的变量插入ident宏中的字符串文字中?换句话说,是否可以“转义”文字的双引号?
// `trace_macros!` requires nightly
#![feature(trace_macros)]
trace_macros!(true);
macro_rules! export_mod_if_feature {
($system:ident) => {
#[cfg(target_os = "$system")] // <-- problem is here
pub mod $system;
};
}
export_mod_if_feature!(linux);
// ... should translate to:
#[cfg(target_os = "linux")]
pub mod linux;
// ... but instead it becomes:
#[cfg(target_os = "$system")]
pub mod linux;
Run Code Online (Sandbox Code Playgroud)
我尝试过使用#[cfg(target_os = stringify!($system))],但cfg需要一个实际的字符串文字target_os =,而不仅仅是一个编译时字符串。
以下代码产生一个警告,但我预计会产生两个警告;我每次写一个CString::new("A CString").unwrap().as_ptr():
use std::ffi::CString;
use std::os::raw::c_char;
extern "C" {
fn puts(s: *const c_char);
}
macro_rules! mymacro {
() => {
puts(CString::new("A CString").unwrap().as_ptr());
};
}
fn main() {
unsafe {
puts(CString::new("A CString").unwrap().as_ptr());
mymacro!();
}
}
Run Code Online (Sandbox Code Playgroud)
warning: getting the inner pointer of a temporary `CString`
--> src/main.rs:16:49
|
16 | puts(CString::new("A CString").unwrap().as_ptr());
| ---------------------------------- ^^^^^^ this pointer will be invalid
| |
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend …Run Code Online (Sandbox Code Playgroud) 这是一个非常小的问题,我知道如何禁用该警告,但阅读它后我怀疑它可能表明我可能对我的宏做了一些不正确的事情。无论如何,我有一个Rational有理数结构:
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Rational {
n: i128,
d: i128,
}
impl Rational {
pub fn new(n: i128, d: i128) -> Self {
Rational { n, d }
}
}
Run Code Online (Sandbox Code Playgroud)
为了以可读的方式创建它们,我使用宏:
macro_rules! rat {
($whole: tt $n : tt / $d : tt) => {
crate::rational::Rational::new($n + $whole * $d, $d)
};
($n : tt / $d : tt) => {
crate::rational::Rational::new($n, $d)
};
($n : tt) => {
crate::rational::Rational::new($n, 1)
};
} …Run Code Online (Sandbox Code Playgroud)