Rust 如何编写基于字符串返回结构的实现方法的宏?
受此启发,我想获得一个基于Rust 如何编写基于字符串返回结构的实现方法的宏?,rust,macros,rust-macros,Rust,Macros,Rust Macros,受此启发,我想获得一个基于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
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
}
最初我想用返回$func_name
获取函数指针,但似乎不可能;标有(***)
的代码行获取错误:
错误[E0423]:应为函数,找到宏“stringify”`
-->src/main.rs:19:22
|
19 |$(如果字符串化($func_name)=索引{
|^^^^^^^^^^^不是函数
...
31 |/comp{
32 | |结构S{
33 | |字段:字符串,
34 | | }
... |
42 | | }
43 | | }
|在这个宏调用中
|
=注意:此错误源于宏(在夜间构建中,使用-Z宏反向跟踪运行以获取更多信息)
帮助:使用“!”调用宏
|
19 |$(如果字符串化!($func_name)=索引{
| ^
错误[E0425]:在此作用域中找不到值'method1'
-->src/main.rs:36:20
|
36 |发布fn方法1(){
|^^^^^^^^在此范围内找不到
错误[E0425]:在此作用域中找不到值'method2'
-->src/main.rs:39:20
|
39 |发布fn方法2(){
|^^^^^^^^在此范围内找不到
错误[E0308]:类型不匹配
-->src/main.rs:19:19
|
19 |$(如果字符串化($func_name)=索引{
| ___________________^
20 | |返回$func_name;/(***)
21 | | })*
||uuuuuuuuuuuuuuuuuuuuuu^预期引用,找到`()`
...
31 |/comp{
32 | |结构S{
33 | |字段:字符串,
34 | | }
... |
42 | | }
43 | | }
|在这个宏调用中
|
=注意:预期引用`&'static(dyn std::ops::Fn()+'static)`
找到的单位类型为“”()`
=注意:此错误源于宏(在夜间构建中,使用-Z宏反向跟踪运行以获取更多信息)
如何完成它?首先,我要感谢@Shepmaster,如果您的问题不复杂,您的建议适用于大多数情况。但是需要解决一个
结构,一个由用户提供的代码块,在这种情况下,我唯一能想到的方法就是使用宏规则来实现它
过了一段时间,我终于完成了。
简言之,就我们而言,我们可以做到
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
}
}
fn获取方法(ind:&str)->选项{
//$name::$func的默认类型是fn(),函数指针
//如果使用了许多方法,建议将其转换为&dyn Fn()
let methods=vec![$(&$name::$func as&dyn Fn()),*];
设inds=vec![$(stringify!($func)),*];
设muti=0;
对于inds.iter()中的项目{
如果项==&ind{
打破
}否则{
i+=1;
}
}
如果我认为您的问题可能由的答案回答。如果不是,请您的问题解释差异。否则,我们可以将此问题标记为已回答。虽然重复返回字段,但返回函数指针应该是等效的。一如既往,在尝试创建宏之前,请先手工编写代码。