我有一个配置结构,其中包含一些顶级属性,我想将其放入各个部分中。我为了提供弃用警告,我制作了以下宏
macro_rules! deprecated {
($config:expr, $old:ident, $section:ident, $new:ident) => {
if $config.$old.is_some() {
println!(
"$old configuration option is deprecated. Rename it to $new and put it under the section [$section]",
);
&$config.$old
} else {
if let Some(section) = &$config.$section {
§ion.$new
} else {
&None
}
}
};
Run Code Online (Sandbox Code Playgroud)
}
这似乎没有按预期工作,因为宏参数没有在字符串中替换。如何改变宏才能达到想要的效果?
我正在尝试编写一个宏来扩展它:
let res = log_request_response!(client.my_call("friend".to_string(), 5));
Run Code Online (Sandbox Code Playgroud)
进入这个:
let res = {
debug!("Request: {}", args_separated_by_commas);
let res = client.my_call("friend".to_string(), 5);
debug!("Response: {}", res);
res
};
Run Code Online (Sandbox Code Playgroud)
到目前为止我的尝试是这样的:
#[macro_export]
macro_rules! log_request_response_to_scuba {
($($client:ident)?.$call:ident($($arg:expr),*);) => {
let mut s = String::new();
$(
{
s.push_str(&format!("{:?}, ", $arg));
}
)*
s.truncate(s.len() - 2);
debug!("Request: {}", s);
// Somehow reconstruct the entire thing with res = at the start.
debug!("Response: {}", res);
res
};
}
Run Code Online (Sandbox Code Playgroud)
但这无法编译:
error: macro expansion ignores token `{` and any following
--> src/main.rs:10:13 …Run Code Online (Sandbox Code Playgroud) 我正在编写一个属性宏并尝试解析那里传递的参数。
喜欢:#[macro(Arg1, Arg2)]
问题是我找不到正确的结构来解析它。我尝试将其解析为MetaandMetaList但它们似乎都不起作用。
pub fn some_macro(args: TokenStream, item: TokenStream) -> TokenStream {
let args_parsed = parse_macro_input!(args as MetaList);
////////
let args_parsed = parse_macro_input!(args as Meta);
}
Run Code Online (Sandbox Code Playgroud)
当我解析它时,MetaList我得到:“意外的输入结束,预期的括号”错误。
我正在创建一个匹配两个表达式和一个标识符的宏.如果不需要,我希望能够忽略标识符,但是如果我_在那里使用,编译器似乎会抱怨.
我的宏:
macro_rules! if_some {
($x:expr, $id:ident, $expr:expr) => {
match $x {
None => None,
Some($id) => Some($expr),
}
};
}
Run Code Online (Sandbox Code Playgroud)
我想做什么:
if_some!(obtain_an_option(), x, do_something_with(x))
Run Code Online (Sandbox Code Playgroud)
和
if_some!(obtain_an_option(), _, do_something())
Run Code Online (Sandbox Code Playgroud)
第二次通话失败.
我通过定义第二个if_some_!没有接收到标识符的宏来解决它(我也不能使用第二个模式).我确定有办法说"这里接受一个标识符或只是_.
也许已经有一个宏/功能(就像Option::map现在我想的那样)......不过现在它很好.
但是,与C和其他语言中的宏不同,Rust宏被扩展为抽象语法树,而不是字符串预处理,因此您不会遇到意外的优先级错误.
为什么抽象语法树比字符串预处理更好?
我正在尝试完成 Rustlings 练习中的测验 #4:
// 编写一个通过测验的宏!这次没有提示,你可以做到!
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_my_macro_world() {
assert_eq!(my_macro!("world!"), "Hello world!");
}
#[test]
fn test_my_macro_goodbye() {
assert_eq!(my_macro!("goodbye!"), "Hello goodbye!");
}
}
Run Code Online (Sandbox Code Playgroud)
我的宏看起来像这样:
#[macro_export]
macro_rules! my_macro {
(($val:expr), "world!") => {
println!("Hello world!");
};
(($val:expr), "goodbye!") => {
println!("Hello goodbye!");
};
}
Run Code Online (Sandbox Code Playgroud)
这是在 Rust 语言文档的声明性宏部分之后设计的。我收到以下错误:
assert_eq!(my_macro!("world!"), "Hello world!");
| ^^^^^^^^^^ no rules expected this token in macro call
assert_eq!(my_macro!("goodbye!"), "Hello goodbye!");
| ^^^^^^^^^^ no rules expected this token in macro call
Run Code Online (Sandbox Code Playgroud)
我找不到解决此问题的解决方案以使其编译。帮助!
在声明性宏中创建标识符时,必须在宏中添加额外的括号(双括号)。我想知道为什么编译器不只是(总是)添加额外的括号。
示例 1:此代码将无法编译,因为在必须使用双括号的情况下仅使用单括号:
macro_rules! some_macro {
() => {
let mut x = 1;
x += 1;
x
};
}
fn main() {
let y = some_macro!();
}
Run Code Online (Sandbox Code Playgroud)
添加双括号解决了编译错误。
示例 2:无论使用单括号还是双括号,此代码都会编译:
macro_rules! some_macro {
() => {{
1
}};
}
fn main() {
let y = some_macro!();
}
Run Code Online (Sandbox Code Playgroud)
是否存在带有双括号的宏破坏单括号宏的情况?如果没有,为什么编译器不总是添加双括号?
我是 Rust 的新手,我在编译以下代码时遇到了问题:
#![feature(trace_macros)]
fn main() {
#[derive(Debug)]
struct Inner {
value: u8
}
#[derive(Debug)]
struct Outer {
inner: Inner
}
let mut x = Outer { inner: Inner { value: 64 } };
/********/
macro_rules! my_macro {
($field_path:expr, $v:expr) => {
x.$field_path = $v;
}
}
trace_macros!(true);
// my_macro!(inner, Inner { value: 42 }); // only works with $field_path:ident
my_macro!(inner.value, 42); // expected output: x.inner.value = 42;
trace_macros!(false);
x . inner.value = 42; // works fine
assert_eq!(42, x.inner.value);
} …Run Code Online (Sandbox Code Playgroud) 是否可以创建一个 Rust 宏来访问作为参数传递的变量的名称和值?
let my_variable: i32 = 5;
printvar!(my_variable); // => to print "my_variable = 5"
Run Code Online (Sandbox Code Playgroud)
例如,对于 C 宏,我们可以使用#运算符:
#include <stdio.h>
#define PRINT_VAR(x) printf("%s = %d\n", #x, x);
int main() {
int my_variable = 5;
PRINT_VAR(my_variable);
}
Run Code Online (Sandbox Code Playgroud)
$ ./a.out
my_variable = 5
Run Code Online (Sandbox Code Playgroud) 我很好奇是否可以更改使用派生宏的结构内部的代码,或者是否仅限于在外部生成新代码?
例子
通过 SomeMacro 将另一个字段添加到 Building 结构中。
#[derive(SomeMacro)]
pub struct Building {
colour: String,
// Add height: u8 through derive macro
}
Run Code Online (Sandbox Code Playgroud) 这个maplit板条箱允许哈希图文字作为=>分隔符。我相信不可能使用macro_rules!分隔:符,但是可以使用处理令牌流的宏吗?
是否不可能将{ key: value }样式宏添加到语言中,即使在编译器中也是如此?
我怀疑问题与:类型运算符冲突,但我无法构建一个不明确的示例,其中编译器无法决定以哪种方式解释:.
macro_rules! call_on_self {
($F:ident) => {
self.$F()
}
}
struct F;
impl F {
fn dummy(&self) {}
fn test(&self) {
call_on_self!(dummy);
}
}
Run Code Online (Sandbox Code Playgroud)
以上不起作用:
error[E0424]: expected value, found module `self`
--> src/lib.rs:3:9
|
3 | self.$F()
| ^^^^ `self` value is a keyword only available in methods with `self` parameter
...
11 | call_on_self!(dummy);
| --------------------- in this macro invocation
Run Code Online (Sandbox Code Playgroud)
我希望生成宏
macro_rules! call_on_self {
($F:ident) => {
self.$F()
}
}
struct F;
impl F {
fn dummy(&self) {}
fn test(&self) …Run Code Online (Sandbox Code Playgroud) 我刚刚发现如何看到导致编译错误的扩展宏代码?.是否可以扩展单个宏而不是整个文件?