我必须匹配fn f(s: &[u8]) {
if Some(&b'A') == s.get(5) && Some(&b'X') == s.get(16) &&
(Some(&b'B') == s.get(17) || Some(&b'C') == s.get(18)) {
} else if Some(&b'1') == s.get(4) && Some(&b'2') == s.get(7) && Some(&b'D') == s.get(10) {
}
}
中的字节,并希望简化我的代码。
现在它看起来像这样:
macro_rules! m {
($ch:expr, $pos:expr) => {{
Some(&$ch) == line.get($pos)
}};
($ch1:expr, $ch2:expr, $pos:expr) => {{
Some(&$ch1) == line.get($pos) || Some(&$ch2) == line.get($pos)
}}
}
我知道nom,但它并没有使这个特例变得更简单,尽管我之后使用nom来提取匹配后的数据。
所以我第一次尝试简化代码就是编写这些宏:
macro_rules! match_several {
($($ch:expr, $pos:expr),*, $last_ch:expr, $last_pos:expr) => {{
(Some(&$ch) == line.get($pos) &&)* Some(&$last_ch) == line.get($last_pos)
}}
}
它减少了代码大小,并减少了犯错的可能性, 但我想要更多:
error: local ambiguity: multiple parsing options: built-in NTs expr ('last_ch') or expr ('ch').
--> lib.rs:45:32
|
45 | if match_several!(b'P', 4, b' ', 5, b'A', 12) {
| ------------------------^^^^-------------- in this macro invocation
但是编译器给出了这个错误:
let line: &'static [u8] = b"0123P 6789ABA";
println!("match result {:?}", match_several!(b'P', 4, b' ', 5, b'A', 12));
测试代码:
public interface NService {
@GET("/computers?p=2")
Call<Model> getItems();
}
答案 0 :(得分:4)
将宏更改为:
macro_rules! match_several {
($($ch:expr, $pos:expr),*) => {{
$(Some(&$ch) == line.get($pos))&&*
}}
}
请注意,我使用&&
作为分隔符,我摆脱了$last_ch
和$last_pos
。这是有效的,因为您可以使用除<{1}}或+
之外的任何令牌作为分隔符,而*
是一个令牌。
答案 1 :(得分:3)
在这种情况下,重复模式可以被抽象为一些有用的函数。
#[inline]
fn all_match(s: &[u8], pattern: &[(u8, usize)]) -> bool {
pattern.into_iter().all(|&(b, p)| s.get(p) == Some(&b))
}
#[inline]
fn any_match(s: &[u8], pattern: &[(u8, usize)]) -> bool {
pattern.into_iter().any(|&(b, p)| s.get(p) == Some(&b))
}
fn f(s: &[u8]) {
let and_pattern = [(b'A', 5), (b'X', 16)];
let or_pattern = [(b'B', 17), (b'C', 18)];
if all_match(s, &and_pattern)
&& any_match(s, &or_pattern) {
} else if all_match(s, &[(b'1', 4), (b'2', 7), (b'D', 10)]) {
}
}