我想写一个macro_rules!
宏,其参数是一个ident
和一个字符串文字列表。宏的扩展需要包含字符串文字和相应的字节文字。该宏用于测试,并且仅用于仅包含U + 0000 ... U + 007F范围内的字符的字符串。如果向宏提供除字符串文字之外的任何内容都会导致编译时错误。
如果目前不能使用程序宏,那么请告诉我,不要费心实际编写程序宏; - )
所需的调用和扩展如下:
all_s! isalpha [ "abcdefghijklmnopqrstuvwxyz" /* , ... */ ];
=>
assert!(isalpha("abcdefghijklmnopqrstuvwxyz"));
assert!("abcdefghijklmnopqrstuvwxyz".chars().all(|b| isalpha(b));
assert!(isalpha(b"abcdefghijklmnopqrstuvwxyz"));
assert!(b"abcdefghijklmnopqrstuvwxyz".iter().all(|b| isalpha(b)));
/* ... */
就我而言:
macro_rules! all_s {
($what: ident, $( $str: tt ),* ) => {{
$(
assert!($what($str));
assert!($str.chars().all(|b| $what(b));
assert!($what(BYTE_LITERAL!($str)));
assert!(BYTE_LITERAL!($str).iter().all(|b| $what(b)));
)*
}}
}
但我不知道在BYTE_LITERAL!
的位置放置什么,而且我收到的错误消息表明我没有正确地写出匹配模式,例如: “宏all_s!期待没有ident参数,给'isalpha'”当'$ what:ident'就在那里。
答案 0 :(得分:1)
我也不知道如何拒绝不是字符串文字的
tt
。
如果你利用参数是字符串这一事实,那么类型检查器将负责产生错误。
macro_rules! all_s {
($what: ident, $( $str: tt ),* ) => {{
$(
assert!($what($str));
assert!(str::chars($str).all(|c| char::is_alphabetic(c)));
assert!(str::chars($str).all(|c| char::is_alphabetic(c)));
)*
}}
}
在您的问题代码中,您尝试使用具有isalpha
和char
值的相同u8
。您必须先将char
转换为u8
:
assert!(str::chars($str)
.map(|c| c as u8) // this is safe given the assumption you stated
.all(|b| b < 0x7F));
答案 1 :(得分:1)
您无法将文字转换为其他类型的文字;它不是宏的工作方式。
你可以通过str::as_bytes
将&str
转换为&[u8]
:
fn is_alpha<T>(_: T) -> bool { true }
macro_rules! all_s {
($what: ident, $str: tt) => {{
assert!($what($str));
assert!($str.chars().all(|b| $what(b)));
assert!($what($str.as_bytes()));
assert!($str.as_bytes().iter().all(|b| $what(b)));
}};
}
fn main() {
all_s!(is_alpha, "abcdefghijklmnopqrstuvwxyz");
}