2016-11-13 18 views
5

Khi xác định triển khai trong macro, có thể hữu ích khi truy cập loại cấu trúc thành viên để tránh phải chuyển nó thành đối số bổ sung. (xem this question)Có thể truy cập loại thành viên cấu trúc cho chữ ký chức năng hoặc khai báo không?

impl PartialEq<u32> for MyStruct { ... } 

Có cách nào để truy cập loại cấu kiện mà không biết trước loại đó?

impl PartialEq<typeof(MyStruct.member)> for MyStruct { ... } 

Trong trường hợp đó là hữu ích, đây là một ví dụ viết tắt của lý do tại sao tôi quan tâm để làm điều này:

struct_bitflag_impl!(
    pub struct MyFlag(u8);, 
    MyFlag, u8); 

//   ^^ how to avoid having this extra arg? 
//    (Used by ``impl PartialEq<$t_internal> for $p``) 
//    couldn't it be discovered from `MyFlag.0` ? 

// the macro 

macro_rules! struct_bitflag_impl { 
    ($struct_p_def: item, $p:ident, $t_internal:ty) => { 

     #[derive(PartialEq, Eq, Copy, Clone, Debug)] 
     $struct_p_def 

     impl ::std::ops::BitAnd for $p { 
      type Output = $p; 
      fn bitand(self, _rhs: $p) -> $p { $p(self.0 & _rhs.0) } 
     } 
     impl ::std::ops::BitOr for $p { 
      type Output = $p; 
      fn bitor(self, _rhs: $p) -> $p { $p(self.0 | _rhs.0) } 
     } 
     impl ::std::ops::BitXor for $p { 
      type Output = $p; 
      fn bitxor(self, _rhs: $p) -> $p { $p(self.0^_rhs.0) } 
     } 

     impl ::std::ops::Not for $p { 
      type Output = $p; 
      fn not(self) -> $p { $p(!self.0) } 
     } 

     // support comparison with the base-type. 
     impl PartialEq<$t_internal> for $p { 
      fn eq(&self, other: &t_internal) -> bool { 
       self.0 == *other 
      } 
     } 
     // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
     //  How to avoid using 't_internal' here? 
    } 
} 
+0

Nhận xét từ @keepr, điều này có thể được xử lý bởi 'custom_derive' xem: https://docs.rs/custom_derive/*/custom_derive/index.html – ideasman42

Trả lời

4

Không, một vị tướng typeof(Type::field) có thể được sử dụng ở vị trí loại không không tồn tại.


Về ví dụ trong câu hỏi, có vẻ như bạn đang mong đợi một loại mục đặc biệt: một cấu trúc tuple chỉ có một trường. Vì vậy, thay vì chấp nhận một mảnh $item, bạn có thể mô phỏng các cú pháp bản thân:

macro_rules! foo { 
    (pub struct $name:ident ($ty:ident)) => { 
     pub struct $name($ty); 

     impl $name { 
      pub fn bar() { 
       println!("{}", stringify!($ty)); 
      } 
     } 
    } 
} 

foo!(
    pub struct Peter(u8) 
); 

fn main() { 
    Peter::bar(); 
} 

Bằng cách đó bạn chỉ cần xác định tất cả mọi thứ cùng một lúc. Tuy nhiên, điều này rõ ràng chỉ hoạt động với một loại định nghĩa tuple-struct, không phải tất cả các loại mục. Nhưng trường hợp sử dụng của bạn cho thấy rằng bạn ít nhiều quan tâm đến trường hợp đặc biệt này.

Nếu bạn muốn cho phép các loại định nghĩa cấu trúc khác nhau, bạn chỉ cần thêm nhiều quy tắc macro vào macro để cho phép cú pháp khác nhau. Để xem ví dụ, here is code to allow for pub and non-pub tuple-struct definitions. Nhưng điều này có thể được mở rộng hơn nữa.

+0

Không phải mã này công khai/riêng tư cho cả cấu trúc và thành viên nội bộ của nó? ví dụ, bạn có thể muốn làm 'struct Peter (pub u8)' hoặc 'pub struct Peter (u8)' – ideasman42

+0

@ ideasman42 Tuyệt đối, điều này rất khó mã hóa cho một trường hợp cụ thể. Nếu bạn muốn sự linh hoạt của 'pub' và non-'pub' bạn có thể thêm macro" arms "... cho phép tôi cố gắng xây dựng một phiên bản đẹp hơn và liên kết nó trong câu hỏi. Vui lòng chờ ;-) –

+0

Tuyệt vời, đã cập nhật mã của tôi để sử dụng kiểu macro này https://gitlab.com/ideasman42/bmesh-rs/blob/master/bmesh/src/bitflag_macros.rs - vẫn không chắc chắn cách 'Peter (u8) 'và' Peter (pub u8) 'sẽ được thực hiện mặc dù. – ideasman42

Các vấn đề liên quan