2017-01-14 19 views
2

매크로에 전달되는 메서드 집합을 제공하는 struct을 생성하는 매크로를 만들려고합니다. 예를 들어, 전화 :매크로에 전달 된 항목 arg를 메소드로 사용할 수 있습니까?

create_impl!(StructName, fn foo() -> u32 { return 432 }) 

빈 구조체 방법 foo()을 제공 StructName을 생성해야합니다.

내 첫 시도는 item 매크로 유형을 사용합니다. 나는 시도하고 규칙에 item를 사용할 때, 나는 다음과 같은 컴파일러 오류 얻을 :

error: expected one of `const`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `fn foo() -> u32 { return 42; }` 
    --> src/lib.rs:40:13 
    | 
40 |   $($function)* 
    |    ^^^^^^^^^ 

그것이 생성 된 구조체에이 방법을 방법을 정의하는 item 인수를 사용할 수 있습니까? 내가 빠진 것이 있습니까?

macro_rules! create_impl { 

    ($struct_name:ident, $($function:item),*) => { 
     struct $struct_name { 
     } 

     impl $struct_name { 
      // This is the part that fails. 
      $($function)* 
     } 
    }; 

} 
+1

* 방법 *은 전혀 항목이 아니라고 생각합니다.'fn foo()'를'fn foo (self)'로 변경하면 * 오류가 발생합니다 :'::'또는':'중 하나가 발견되면')'* (외부에 쓰면 같은 오류가 발생합니다 매크로). –

답변

1

짧은 대답은 "아니오, 당신은 방법에 대한 item 정규를 사용할 수 없습니다"입니다 :

은 여기에 정의한 전체 매크로입니다.

reference에 따르면 항목은 상자 나 모듈의 최상위 항목이므로 함수, 유형 등이 있습니다. struct 또는 impl 블록이 항목이지만 내부 항목은 그렇지 않습니다. 문법적으로는 메소드 정의가 최상위 함수와 동일하게 보이지만 항목 정의는 아닙니다.

녹의 매크로 시스템이 작동하는 방식은 단편이 item으로 파싱 된 경우입니다. $foo:item을 사용하면 영원히 item이됩니다. 매크로가 확장되면 다시 파싱하기 위해 토큰으로 분할됩니다.

이 결과는 $foo:item은 일반적으로 최상위 항목을 의미하는 항목 위치에서 매크로 출력에만있을 수 있다는 것입니다.

몇 가지 대안이 있습니다.

가장 간단한 것은 tt (토큰 트리) 정규 표현터를 사용하는 것입니다. 토큰 트리는 대괄호가 아닌 토큰이거나 균형 잡힌 대괄호로 묶인 토큰 시퀀스입니다. 그래서 $(foo:tt)*은 무엇이든 일치합니다. 그러나 각 항목 주위에 괄호를 추가하는 것이 더 쉽기 때문에 쉼표도 함께 사용하게되므로 각 항목 주위에 중괄호를 추가하는 것이 더 쉽습니다.

macro_rules! create_impl {

($struct_name:ident, $({ $($function:tt)* }),*) => { 
     struct $struct_name { 
     } 

     impl $struct_name { 
      $($($function)*)* 
     } 
    }; 

} 

그럼 당신은 여분의 중괄호를 사용할 필요가 :

macro_rules! create_impl2 { 
    ($struct_name:ident, $(fn $fname:ident($($arg:tt)*) -> $t:ty $body:block),*) => { 
     struct $struct_name { 
     } 

     impl $struct_name { 
      $(fn $fname($($arg)*) -> $t $body)* 
     } 
    } 
} 
:

create_impl!(StructName, { fn foo() -> u32 { return 432 } }, { fn bar() -> u32 { return 765 } }); 

또한 단지 오히려 item 정규에 위임하는 대신, 직접 원하는 구문을 일치시킬 수 있습니다

물론 명시 적이므로 반환 유형없이 함수를 지원하려면 매크로에 다른 사례를 추가해야합니다.