如何编写一个 returns 基于字符串的结构实现方法的宏?

How do I write a macro that returns the implemented method of a struct based on a string?

受到的启发,我想获得一个基于str的结构的实现方法,类似于:

macro_rules! comp {
    (struct $name:ident {
        $($field_name:ident : $field_type:ty,)*
    }
    impl $name2:ident {
        $(pub fn $func_name:ident($($args:tt)*) $bk:block)*
    }

    ) => {
        //basic component
        struct $name {
            $($field_name: $field_type),*
        }
        impl $name {
            $(pub fn $func_name($($args)*) $bk)*

            // the generated function
            pub fn get_method(index: &str) -> &'static dyn Fn() {
                $(if stringify!($func_name) == index {
                    return $func_name;                               // (***)
                })*
                //
                // Some code here to return the right function
                //
            }
        }
    };
}

fn main() {
    comp! {
        struct S {
            field: String,
        }
         impl S {
            pub fn method1() {
                println!("method1 called");
            }
            pub fn method2() {
                println!("method2 called");
            }
        }
    }
    // the functionality should achieved
    // S::get_method("method1") == S::method1
    // S::get_method("method2") == S::method2
}

本来想用return $func_name获取函数指针,但是好像不行;标有 (***) 的代码行出现错误:

error[E0423]: expected function, found macro `stringify`
  --> src/main.rs:19:22
   |
19 |                   $(if stringify($func_name) == index {
   |                        ^^^^^^^^^ not a function
...
31 | /     comp! {
32 | |         struct S {
33 | |             field: String,
34 | |         }
...  |
42 | |         }
43 | |     }
   | |_____- in this macro invocation
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
help: use `!` to invoke the macro
   |
19 |                 $(if stringify!($func_name) == index {
   |                               ^

error[E0425]: cannot find value `method1` in this scope
  --> src/main.rs:36:20
   |
36 |             pub fn method1() {
   |                    ^^^^^^^ not found in this scope

error[E0425]: cannot find value `method2` in this scope
  --> src/main.rs:39:20
   |
39 |             pub fn method2() {
   |                    ^^^^^^^ not found in this scope

error[E0308]: mismatched types
  --> src/main.rs:19:19
   |
19 |                   $(if stringify($func_name) == index {
   |  ___________________^
20 | |                     return $func_name;                               // (***)
21 | |                 })*
   | |_________________^ expected reference, found `()`
...
31 | /     comp! {
32 | |         struct S {
33 | |             field: String,
34 | |         }
...  |
42 | |         }
43 | |     }
   | |_____- in this macro invocation
   |
   = note: expected reference `&'static (dyn std::ops::Fn() + 'static)`
              found unit type `()`
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

如何完成?

首先感谢@Shepmaster,如果你的问题不复杂,你的建议对大多数情况都是适用的。然而,它需要处理 struct,用户提供的一段代码,在这种情况下,我想出的唯一方法是使用宏规则来实现

经过一段时间,我终于搞定了。 在我们的例子中,简而言之,我们可以做

fn get_method(ind: &str) -> Option<&dyn Fn()> {
    // the default type of $name::$func is fn(), function pointer
    // it is recommended to convert into &dyn Fn() if you impl many methods
    let methods = vec![ $(&$name::$func as &dyn Fn()),* ];
    let inds = vec![$(stringify!($func)),*];
    let mut i = 0;
    for item in inds.iter() {
        if item == &ind {
            break;
        } else {
            i +=1;
        }
     }
     if i <= inds.len() - 1 {
         Some(methods[i])
     } else {
         None
     }
     
}