我有一个程序属性宏,它给定一个函数对每个二进制表达式进行操作,例如let a = b + c;
并根据它返回另一个表达式。随着+
操作取决于类型,它需要知道类型a
, b
and c
.
有没有办法在编译时获取变量的推断类型?
(就像 rust-analysisr 可能会显示推断的类型一样,我可以在宏中获取这些类型吗?)
简单的例子 -
为了在 Rust 游乐场中更简洁地说明我的方法,我们可以使用声明性宏来调用给定变量上的函数,该函数的细节基于给定变量的类型。
我在 Rust 游乐场中最接近我想要的功能:
macro_rules! SomeMacro {
($x:expr) => {{
$x.some_function(3.)
}};
}
trait SomeTrait {
fn some_function(&self,x:f32) -> f32;
}
impl SomeTrait for u32 {
fn some_function(&self,x:f32) -> f32 {
x * 3.
}
}
fn main() {
let a = 3u32;
let b = SomeMacro!(a);
assert_eq!(b,9.);
}
我怎样才能让事情像这样工作:
fn some_function<u32>(x:f32) -> f32 {
3. * x
}
fn some_function<u32,i8,f32>(x:f32) -> f32 {
3. * x
}
fn main() {
let a = 3u32;
let b = <type_of<a>()>::some_function(3.);
assert_eq!(b,9.);
let c = 5i8;
let d = <type_of<a>(),type_of<b>(),type_of<c>()>::some_function(2.);
assert_eq!(c,6.);
}
综合示例 -.zip https://drive.google.com/file/d/1lT7s9NvdyOaFkgR3NGyrLLMlwThDCrKK/view?usp=sharing
lib.rs
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn my_attribute_macro(_attr: TokenStream, item: TokenStream) -> TokenStream {
let ast = syn::parse_macro_input!(item as syn::Item);
// eprintln!("{:#?}",ast);
// Checks item is function.
let mut function = match ast {
syn::Item::Fn(func) => func,
_ => panic!("Only `fn` items are supported."),
};
let block = &mut function.block;
// Updates statements
let statements = block.stmts
.iter()
.filter_map(|statement| update_statements(statement))
.collect::<Vec<_>>();
block.stmts = statements;
let new = quote::quote! { #function };
TokenStream::from(new)
}
fn update_statements(stmt: &syn::Stmt) -> Option<syn::Stmt> {
let local = match stmt {
syn::Stmt::Local(local) => local,
_ => return Some(stmt.clone())
};
let init = &local.init;
let bin_expr = match *init.as_ref().unwrap().1 {
syn::Expr::Binary(ref bin) => bin,
_ => return Some(stmt.clone())
};
eprintln!("looking at: {:#?}",stmt);
//
None
}
main.rs
use macro_test::*;
// Goals:
// - Map from `x` being equal to `a+b` to `x` being equal to `a*b` based off `x` being `f32`.
// - Map from `y` being equal to `c+d` to `y` being equal to `c/d` based off `y` being `u32`.
#[my_attribute_macro]
fn my_function(a: f32, b: f32, c: u32, d: u32) {
let x = a + b;
let y = c + d;
}
fn main() {
}
其中一张照片看起来像(来自cargo expand --bin macro-test
):
looking at: Local(
Local {
attrs: [],
let_token: Let,
pat: Ident(
PatIdent {
attrs: [],
by_ref: None,
mutability: None,
ident: Ident {
ident: "y",
span: #0 bytes(316..317),
},
subpat: None,
},
),
init: Some(
(
Eq,
Binary(
ExprBinary {
attrs: [],
left: Path(
ExprPath {
attrs: [],
qself: None,
path: Path {
leading_colon: None,
segments: [
PathSegment {
ident: Ident {
ident: "c",
span: #0 bytes(320..321),
},
arguments: None,
},
],
},
},
),
op: Add(
Add,
),
right: Path(
ExprPath {
attrs: [],
qself: None,
path: Path {
leading_colon: None,
segments: [
PathSegment {
ident: Ident {
ident: "d",
span: #0 bytes(324..325),
},
arguments: None,
},
],
},
},
),
},
),
),
),
semi_token: Semi,
},
)