macro_rules! macro采用字符串文字“...”,扩展为“...”和b“......”

时间:2017-02-08 17:50:06

标签: macros rust

我想写一个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'就在那里。

2 个答案:

答案 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)));
        )*
    }}
}

在您的问题代码中,您尝试使用具有isalphachar值的相同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");
}