我有一个自定义结构,如下所示:
struct MyStruct {
first_field: i32,
second_field: String,
third_field: u16,
}
Run Code Online (Sandbox Code Playgroud)
是否有可能以编程方式获取结构字段的数量(例如,通过方法调用field_count()):
let my_struct = MyStruct::new(10, "second_field", 4);
let field_count = my_struct.field_count(); // Expecting to get 3
Run Code Online (Sandbox Code Playgroud)
对于这个结构:
struct MyStruct2 {
first_field: i32,
}
Run Code Online (Sandbox Code Playgroud)
......以下电话应该返回1:
let my_struct_2 = MyStruct2::new(7);
let field_count = my_struct2.field_count(); // Expecting to get count 1
Run Code Online (Sandbox Code Playgroud)
有没有像这样的API field_count()或者只能通过宏获得它?
如果使用宏可以实现这一点,那么应该如何实现?
我正在编写一个程序宏,它工作正常,但我无法以符合人体工程学的方式报告错误.使用panic!"工作"但不优雅,并且不会很好地向用户显示错误消息.
我知道我可以在解析a时报告错误TokenStream,但是在解析之后我需要在遍历AST时产生错误.
宏调用如下所示:
attr_test! {
#[bool]
FOO
}
Run Code Online (Sandbox Code Playgroud)
并应输出:
const FOO: bool = false;
Run Code Online (Sandbox Code Playgroud)
这是宏代码:
extern crate proc_macro;
use quote::quote;
use syn::parse::{Parse, ParseStream, Result};
use syn::{Attribute, parse_macro_input, Ident, Meta};
struct AttrTest {
attributes: Vec<Attribute>,
name: Ident,
}
impl Parse for AttrTest {
fn parse(input: ParseStream) -> Result<Self> {
Ok(AttrTest {
attributes: input.call(Attribute::parse_outer)?,
name: input.parse()?,
})
}
}
#[proc_macro]
pub fn attr_test(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
let test: AttrTest = parse_macro_input!(tokens);
let name = test.name;
let first_att …Run Code Online (Sandbox Code Playgroud) 我正在尝试创建一个proc-macro派生和实现结构的特征,并且我需要结构中的所有字段都实现Display。
我该如何检查?
此外,我如何检查属性是否Iterator也实现了?(我想处理迭代器的项目是否也实现了显示)。
我正在使用syn和quote板条箱。我设法解析struct并生成实现。但对于像Vec和这样的类型Option,我想检查他们是否Iterator正确实现和处理它。
该syn::Field结构具有ty我认为应该作为起点的属性,但是查看文档我无法猜测任何方法来检查此类型是否实现了某种特征。
我编写了一个proc-macro库来配合我正在编写的库 - 它们一起使用,前者用于抽象掉后者中的大量冗余代码。
我在 proc 宏中成功生成了多个结构和实现。我也在使用cargo doc该库,我的文档正是我所期望的。但是,我在 proc 宏中创建的文档注释未按预期工作。我的 proc 宏中的一些代码大致如下所示:
#[proc_macro_derive(MyDerive)]
pub fn derive(input: TokenStream) -> TokenStream {
...
let expanded = quote! {
...
impl #my_struct {
/// This comment doesn't show up in documentation
pub fn foo(&self, n: i32) -> bool {
false
}
/// This comment DOES show up in documentation
pub fn bar(n: i32) -> Vec<String> {
...
}
}
}
expanded.into()
}
Run Code Online (Sandbox Code Playgroud)
当我打开生成的文档时:
foo本身出现在文档中,但其注释没有bar及其评论在文档中bar …在编写声明性 ( macro_rules!) 宏时,我们会自动获得宏卫生。在这个例子中,我声明了一个f在宏中命名的变量并传入一个标识符f,该标识符成为一个局部变量:
macro_rules! decl_example {
($tname:ident, $mname:ident, ($($fstr:tt),*)) => {
impl std::fmt::Display for $tname {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { $mname } = self;
write!(f, $($fstr),*)
}
}
}
}
struct Foo {
f: String,
}
decl_example!(Foo, f, ("I am a Foo: {}", f));
fn main() {
let f = Foo {
f: "with a member named `f`".into(),
};
println!("{}", f);
}
Run Code Online (Sandbox Code Playgroud)
这段代码可以编译,但是如果查看部分展开的代码,您会发现存在明显的冲突:
impl std::fmt::Display …Run Code Online (Sandbox Code Playgroud) 我创建了一个类似函数的程序宏。我用声明性宏作为参数来调用它。我希望找到一种在处理过程宏之前扩展声明性宏的方法(或在过程宏内部扩展它)。示例(代码也可在https://github.com/Jasperav/rec_macro获取):
致电网站:
macro_rules! t {
($e:expr) => {
$e.to_string() + " I am a macro"
}
}
fn main() {
re!(t!("hi"));
}
Run Code Online (Sandbox Code Playgroud)
过程宏箱:
#[proc_macro_hack]
pub fn re(input: TokenStream) -> TokenStream {
panic!("{:#?}", input) // I can see "hi" and something like t!, but not the result of the macro expansion
}
Run Code Online (Sandbox Code Playgroud)
在panic消息中,我看到声明性宏 ( t) 位于其中。我只想要这种情况下的原始值hi I am a macro(或某种syn类型)。就我而言,声明性宏应始终扩展为 a&str或String。
是否可以t在调用之前展开,或者在 proc 宏内手动re展开? …
下面是mod文档给出的例子syn::parse。
enum Item {
Struct(ItemStruct),
Enum(ItemEnum),
}
struct ItemStruct {
struct_token: Token![struct],
ident: Ident,
brace_token: token::Brace,
fields: Punctuated<Field, Token![,]>,
}
impl Parse for Item {
fn parse(input: ParseStream) -> Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(Token![struct]) {
input.parse().map(Item::Struct) // <-- here
} else if lookahead.peek(Token![enum]) {
input.parse().map(Item::Enum) // <-- and here
} else {
Err(lookahead.error())
}
}
}
Run Code Online (Sandbox Code Playgroud)
是input.parse().map(Item::Struct)有效的普通 Rust 语法(看起来不是Item::Struct函数),还是库的一种特殊语法proc_macro?如果是后者,是否有proc_macro具体语法规则的文档?
我创建了一个实现特征的程序宏,但为了使其工作,我需要获取每个字段的原始字节。问题是如何获取字段的字节取决于字段的类型。
有没有某种方法可以测试某个函数是否存在于某个字段以及它是否不尝试另一个函数?
例如这样的事情:
if item.field::function_exist {
//do code
} else {
//do other code
}
Run Code Online (Sandbox Code Playgroud)
目前,我正在考虑创建另一个特征/成员函数,我只需为所有原语创建它,并为更大的字段(例如结构)创建一个程序宏。例如:
if item.field::as_bytes().exists {
(&self.#index).as_bytes()
} else {
let bytes = (&self.#index).to_bytes();
&bytes
}
Run Code Online (Sandbox Code Playgroud)
对于字符串,它有as_bytes成员函数,而对于字符串则i32没有。这意味着当结构的成员字段不是字符串时,我需要额外的代码。我可能需要 amatch而不是 an if,但是if对于这个例子来说就足够了。
应该如何a_proc_macro定义以便它“返回”一个 5?
fn main() {
let a = a_proc_macro!();
assert!(a == 5);
}
Run Code Online (Sandbox Code Playgroud) 我需要获取每个方法的调用者的源位置。我正在尝试创建一个proc_macro_attribute来捕获位置并打印它。
#[proc_macro_attribute]
pub fn get_location(attr: TokenStream, item: TokenStream) -> TokenStream {
// Get and print file!(), line!() of source
// Should print line no. 11
item
}
Run Code Online (Sandbox Code Playgroud)
#[get_location]
fn add(x: u32, y: u32) -> u32 {
x + y
}
fn main() {
add(1, 5); // Line No. 11
}
Run Code Online (Sandbox Code Playgroud)