简体   繁体   English

如何在Rust宏中使用ty

[英]How to use ty in a Rust macro

I'm try to compose a generic solution to provide fixtures for unit testing Rust code. 我试图编写一个通用的解决方案,为单元测试Rust代码提供夹具。 I have come up with a macro, which allows the user to define setup and teardown methods. 我想出了一个宏,它允许用户定义设置拆卸方法。 Here is my solution so far: 这是我到目前为止的解决方案:

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");
});

This works. 这有效。 The only problem is, that the macro unit_test is not generic, and is bound to the fixture name FooTestFixture . 唯一的问题是,宏unit_test不是通用的,并且绑定到夹具名称FooTestFixture This means that each test module needs to redefine this macro for every test fixture, which is not ideal. 这意味着每个测试模块都需要为每个测试夹具重新定义这个宏,这是不理想的。 What I'd like to be able to do is to also introduce a type variable and use that type in the macro expansion. 我希望能够做的是引入一个类型变量并在宏扩展中使用该类型。 Delving more into macros I have found that there is a 'ty' item, that represents a type, and I thought I could do this ... 深入研究宏我发现有一个'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");
});

However, this doesn't work and results in the following error: 但是,这不起作用并导致以下错误:

src\\tests\\heap_fixture_with_new.rs:48:40: 48:50 error: $ftype:ty is followed by $expr:expr , which is not allowed for ty fragments src\\tests\\heap_fixture_with_new.rs:48 ($name:ident $fixt:ident $ftype:ty $expr:expr) => ( src \\ tests \\ heap_fixture_with_new.rs:48:40:48:50错误: $ftype:ty后跟$expr:expr ,不允许使用ty片段src \\ tests \\ heap_fixture_with_new.rs:48($ name:ident $ fixt:ident $ ftype:ty $ expr:expr)=>(

As you can see, in the macro definition, I have replaced references to FooTestFixture with $ftype. 如您所见,在宏定义中,我用$ ftype替换了对FooTestFixture的引用。

Is what I'm trying to achieve possible? 我正在努力实现的目标是什么? It's almost like I'd like the macro to be generic, allowing you to pass in a type, to be used inside the macro definition. 这几乎就像我希望宏是通用的,允许你传入一个类型,在宏定义中使用。

A ty cannot be directly followed by an expr . 一个ty不能直接跟一个expr It must be followed by a specific set of tokens : 必须跟着一组特定的令牌

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

Similar restriction exists after an expr , stmt , path and pat . exprstmtpathpat之后存在类似的限制。 This was introduced in RFC 550 to future-proof potential change in Rust syntax . 这是在RFC 550中引入的, 用于防止Rust语法中面向未来的潜在变化

To fix it you need to change your macro's pattern, eg 要修复它,您需要更改宏的模式,例如

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

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

Well I realised I didn't need ty after all. 好吧,我意识到我毕竟不需要ty I can just specify the type as an ident parameter so the following does work: 我可以将类型指定为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");
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM