如何在Rust宏中使用ty

4

我试图为单元测试Rust代码提供通用的解决方案。我想到了一个宏,允许用户定义设置拆卸方法。以下是我的解决方案:

struct FooTestFixture {
    pub name : String
}

impl FooTestFixture {
    fn setup() -> FooTestFixture {
        FooTestFixture { name: String::from("Initialised") }
    }
}

fn teardown(fixture : &mut FooTestFixture) {
    fixture.name = "".to_string();
}

macro_rules! unit_test {
    ($name:ident $fixt:ident $expr:expr) => (
        #[test]
        fn $name() {
            let mut $fixt : FooTestFixture = FooTestFixture::setup();
            $expr;

            teardown(&mut $fixt);
        }
    )
}

unit_test! (heap_foo_fixture_should_be_initialised_using_macro f {
    assert_eq!(f.name, "Initialised");
});

这个可以用。唯一的问题是,宏unit_test不是通用的,并且绑定到fixture名称FooTestFixture。这意味着每个测试模块都需要为每个测试fixture重新定义此宏,这并不理想。我希望能够引入一个类型变量,并在宏扩展中使用该类型。深入研究宏后,我发现有一个'ty'项,表示一种类型,我认为我可以这样做...

macro_rules! unit_test {
    ($name:ident $fixt:ident $ftype:ty $expr:expr) => (
        #[test]
        fn $name() {
            let mut $fixt : $ftype = $ftype::setup();
            $expr;

            teardown(&mut $fixt);
        }
    )
}

unit_test! (heap_foo_fixture_should_be_initialised_using_macro FooTestFixture f {
    assert_eq!(f.name, "Initialised");
});

然而,这并不起作用,导致以下错误:

src\tests\heap_fixture_with_new.rs:48:40: 48:50 error: $ftype:ty后面跟着$expr:expr,对于ty片段是不允许的 src\tests\heap_fixture_with_new.rs:48 ($name:ident $fixt:ident $ftype:ty $expr:expr) => (

如您所见,在宏定义中,我已将 FooTestFixture 的引用替换为 $ftype。
我试图实现的目标是否可行?这就像我希望宏是通用的,可以传入一种类型,在宏定义中使用。
2个回答

3

我意识到我其实不需要ty。我可以通过将类型指定为ident参数来使下面的代码正常工作:

macro_rules! unit_test {
    ($name:ident $fixt:ident $ftype:ident $expr:expr) => (
        #[test]
        fn $name() {
            let mut $fixt = $ftype::setup();
            $expr;

            teardown(&mut $fixt);
        }
    )
}

unit_test! (foo_fixture_should_be_initialised_using_generic_macro f FooTestFixture {
    assert_eq!(f.name, "Initialised");
});

3

ty不能直接跟在expr后面。它必须跟着一组特定的标记:

  • =>
  • ,
  • =
  • |
  • ;
  • :
  • >
  • [
  • {
  • as
  • where

类似的限制也存在于exprstmtpathpat之后。这是为了使Rust语法更具未来性而在RFC 550中引入的。

要解决这个问题,需要更改你的宏模式,例如:

macro_rules! unit_test {
    ($name:ident $fixt:ident<$ftype:ty> $expr:expr) => (
//                          ^         ^ followed by '>' is OK

unit_test! (test_name fixture_name<FooTestFixture> f {    
//                                ^              ^

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接