Macros 宏规则只匹配第一个模式
我为sym链接文件编写了一个宏。起初我只有第一个模式,但后来我想不必一直写“&format!”就好了 因此,根据这些模式:Macros 宏规则只匹配第一个模式,macros,rust,Macros,Rust,我为sym链接文件编写了一个宏。起初我只有第一个模式,但后来我想不必一直写“&format!”就好了 因此,根据这些模式: macro_rules! syml { ($a:expr, $b:expr) => { Command::new("ln").args(&["-s", $a, $b]) }; ( ($a:expr, $($x:expr),+), ($b:expr, $($y:expr),+) ) => { Comm
macro_rules! syml {
($a:expr, $b:expr) => {
Command::new("ln").args(&["-s", $a, $b])
};
( ($a:expr, $($x:expr),+), ($b:expr, $($y:expr),+) ) => {
Command::new("ln").args(&["-s", &format!($a, $($x),+), &format!($b, $($y),+)])
}
}
我想匹配这些情况:
syml!("from", "to");
syml!(("{}", from), "to");
syml!("from", ("{}", to));
syml!(("{}", from), ("{}", to));
syml!(("{}{}", from, here), ("{}{}", to, there));
但是到目前为止,每次只有第一个模式匹配,所以我得到了不匹配的类型
错误,比如预期引用,find tuple
我不明白为什么,即使是最后两个示例,它也会尝试匹配第一种模式而不是第二种模式。正如@MatthieuM在一篇评论中指出的,元组是一个表达式,宏规则是按顺序尝试的 因此,在你的情况下:
macro_rules! syml {
($a:expr, $b:expr) => {
Command::new("ln").args(&["-s", $a, $b])
};
( ($a:expr, $($x:expr),+), ($b:expr, $($y:expr),+) ) => {
Command::new("ln").args(&["-s", &format!($a, $($x),+), &format!($b, $($y),+)])
}
}
第一条规则将始终与第二条规则匹配。解决方案是将它们互换:
macro_rules! syml {
( ($a:expr, $($x:expr),+), ($b:expr, $($y:expr),+) ) => {
Command::new("ln").args(&["-s", &format!($a, $($x),+), &format!($b, $($y),+)])
};
($a:expr, $b:expr) => {
Command::new("ln").args(&["-s", $a, $b])
}
}
()
上面没有介绍混合元组和字符串的两个测试用例:
syml!(("{}", from), "to");
syml!("from", ("{}", to));
这可以通过添加新案例(按顺序)简单地解决。(我不知道是否有可能排除元组/字符串匹配,但我有兴趣看到任何解决方案。)
()不是宏专家,所以我只想简单指出两点:(1)元组是一个表达式,因此“(x,y)”可以匹配
$a:expr
,(2)我相信这些模式是按顺序尝试的。。。您是否尝试过先放置更具体的模式?与问题无关,但标准库有一个函数。当然,元组是一个表达式!我完全错过了,谢谢。还要感谢@MatthieuM。感谢您对我的两个未覆盖测试用例进行编辑并提供修复!一个规则更少的解决方案确实很有趣。也许我可以在深入研究铁锈宏之后找到一个;我真的很少玩宏:)
macro_rules! syml {
( ($a:expr, $($x:expr),+), ($b:expr, $($y:expr),+) ) => {
Command::new("ln").args(&["-s", &format!($a, $($x),+), &format!($b, $($y),+)])
};
( $a:expr, ($b:expr, $($y:expr),+) ) => {
Command::new("ln").args(&["-s", $a, &format!($b, $($y),+)])
};
( ($a:expr, $($x:expr),+), $b:expr ) => {
Command::new("ln").args(&["-s", &format!($a, $($x),+), $b])
};
($a:expr, $b:expr) => {
Command::new("ln").args(&["-s", $a, $b])
}
}