宏中的动态结构键
Dynamic struct key in macro
有没有办法让这两个宏成为同一个宏?
macro_rules! bg_color_test {
($($color:path, $flag:literal),*$(,)?) => {
let mut options = Options::default();
options.text = String::from("my text");
$(
options.background = $color;
assert_eq!(
parse_args(vec![
"path/to/bin".to_string(),
"my text".to_string(),
"-b".to_string(),
$flag.to_string()
]),
options
);
)*
}
}
// used like below:
bg_color_test!(
Colors::Red,"red",
Colors::Green,"green",
Colors::Blue,"blue",
);
还有这个:
macro_rules! color_test {
($($color:expr, $flag:literal),*$(,)?) => {
let mut options = Options::default();
options.text = String::from("my text");
$(
options.colors = $color;
assert_eq!(
parse_args(vec![
"path/to/bin".to_string(),
"my text".to_string(),
"-c".to_string(),
$flag.to_string()
]),
options
);
)*
}
}
// used like below:
color_test!(
vec![Colors::Red],"red",
vec![Colors::Green],"green",
vec![Colors::Blue],"blue",
);
我正在为这个问题苦苦挣扎:
options.background = $color;
vs options.colors = $color;
...不知道如何将其构建到宏中...
在宏中,我尝试在下面使密钥动态化:
options.$kind = $color; // syntax error
options[$kind] = $color; // syntax error
options.$($kind)* = $color; // empty expression error
我使用宏的方式是这样的:
bg_color_test!(
"background", Colors::Red,"red",
"background", Colors::Green,"green",
"background", Colors::Blue,"blue",
);
哪个会给我:
error: no rules expected the token `"background"`
--> tests/parse_args_test.rs:491:3
|
464 | macro_rules! bg_color_test {
| ------------------------ when calling this macro
...
491 | "background", BgColors::Red, "red",
| ^^^^^^^^^^^^ no rules expected this token in macro call
error: could not compile `lib` due to previous error
我在用户 @pie_flavor
的帮助下在 Discord 上找到了答案。
我的错误是在宏调用中将关键参数视为 str
,它应该是 ident
作为开始的参数。
所以将这两个宏合并在一起的最终代码是:
macro_rules! color_test {
($($kind:ident, $color:expr, $flag:literal, $flag_value:literal),*$(,)?) => {
let mut options = Options::default();
options.text = String::from("my text");
$(
options.$kind = $color;
assert_eq!(
parse_args(vec![
"path/to/bin".to_string(),
"my text".to_string(),
$flag.to_string(),
$flag_value.to_string()
]),
options
);
)*
}
}
这样使用:
color_test!(
colors, vec![Colors::Red], "-c", "red",
background, Colors::Green, "-b", "green",
);
有没有办法让这两个宏成为同一个宏?
macro_rules! bg_color_test {
($($color:path, $flag:literal),*$(,)?) => {
let mut options = Options::default();
options.text = String::from("my text");
$(
options.background = $color;
assert_eq!(
parse_args(vec![
"path/to/bin".to_string(),
"my text".to_string(),
"-b".to_string(),
$flag.to_string()
]),
options
);
)*
}
}
// used like below:
bg_color_test!(
Colors::Red,"red",
Colors::Green,"green",
Colors::Blue,"blue",
);
还有这个:
macro_rules! color_test {
($($color:expr, $flag:literal),*$(,)?) => {
let mut options = Options::default();
options.text = String::from("my text");
$(
options.colors = $color;
assert_eq!(
parse_args(vec![
"path/to/bin".to_string(),
"my text".to_string(),
"-c".to_string(),
$flag.to_string()
]),
options
);
)*
}
}
// used like below:
color_test!(
vec![Colors::Red],"red",
vec![Colors::Green],"green",
vec![Colors::Blue],"blue",
);
我正在为这个问题苦苦挣扎:
options.background = $color;
vs options.colors = $color;
...不知道如何将其构建到宏中...
在宏中,我尝试在下面使密钥动态化:
options.$kind = $color; // syntax error
options[$kind] = $color; // syntax error
options.$($kind)* = $color; // empty expression error
我使用宏的方式是这样的:
bg_color_test!(
"background", Colors::Red,"red",
"background", Colors::Green,"green",
"background", Colors::Blue,"blue",
);
哪个会给我:
error: no rules expected the token `"background"`
--> tests/parse_args_test.rs:491:3
|
464 | macro_rules! bg_color_test {
| ------------------------ when calling this macro
...
491 | "background", BgColors::Red, "red",
| ^^^^^^^^^^^^ no rules expected this token in macro call
error: could not compile `lib` due to previous error
我在用户 @pie_flavor
的帮助下在 Discord 上找到了答案。
我的错误是在宏调用中将关键参数视为 str
,它应该是 ident
作为开始的参数。
所以将这两个宏合并在一起的最终代码是:
macro_rules! color_test {
($($kind:ident, $color:expr, $flag:literal, $flag_value:literal),*$(,)?) => {
let mut options = Options::default();
options.text = String::from("my text");
$(
options.$kind = $color;
assert_eq!(
parse_args(vec![
"path/to/bin".to_string(),
"my text".to_string(),
$flag.to_string(),
$flag_value.to_string()
]),
options
);
)*
}
}
这样使用:
color_test!(
colors, vec![Colors::Red], "-c", "red",
background, Colors::Green, "-b", "green",
);