短版
简短的版本是:当编写一个过程宏wrap
来 Package 一个函数时(有点像trace crate的方式),要求所有参数实现一个特定的trait的最佳方法是什么?
问题是
trace
扩展到对println!("{:?}", i)
的调用,因此:
struct MyType(u32);
#[trace]
fn foo(i: MyType) {
println!("MyType: {}", i.0);
}
字符串
我明白
error[E0277]: `MyType` doesn't implement `Debug`
--> src/main.rs:10:8
|
9 | #[trace]
| ------- in this procedural macro expansion
10 | fn foo(i: MyType) {
| ^ `MyType` cannot be formatted using `{:?}`
|
= help: the trait `Debug` is not implemented for `MyType`
型
这是很好的和明确的:它显示了参数声明中的错误,并指出MyType应该实现Debug。
现在我尝试做同样的事情,但扩展到类似MyTrait::my_trait_method(&i)
的东西,仍然得到基本相同的错误消息。
我所尝试的
到目前为止,我所能做的最好的就是在通过quote!
宏生成的扩展中添加Where子句(我仍然在弄清楚如何使用syn
crate,所以它仍然是硬编码的),至少我确实得到了一条明确的消息,说MyType
没有实现MyTrait
,但错误是在宏上报告的,而不是在参数定义上:
#[proc_macro_attribute]
pub fn wrap(_macro_args: TokenStream, input: TokenStream) -> TokenStream {
let func = parse_macro_input!(input as syn::ItemFn);
let orig_name = func.sig.ident.to_string();
let params: Punctuated<Pat, Token![,]> = func
.sig
.inputs
.iter()
.map(|input| match input {
FnArg::Typed(PatType { pat: t, .. }) => t.as_ref().clone(),
_ => panic!("Unexpected input for function {orig_name}: {input:?}"),
})
.collect();
let pattern = "{:?}, ".repeat(params.len());
quote! {
fn foo(i: MyType) where MyType: MyTrait{
//i.my_trait_method();
println!(#pattern, #params);
}
}
.into()
}
x
#[trace]
fn foo(i: MyType) {
println!("MyType: {}", i.0);
}
error[E0277]: the trait bound `MyType: MyTrait` is not satisfied
--> src/main.rs:11:1
|
11 | #[wrap]
| ^^^^^^^ the trait `MyTrait` is not implemented for `MyType`
的一种或多种
是生成Where子句的方法吗(如果是这样的话,我会正确地做),或者有更好的方法来要求在proc_macro中解析的函数的所有参数都有特定的trait?
2条答案
按热度按时间xjreopfe1#
虽然Chayim Friedman的答案是正确的,但我想补充的是,您仍然可以使用标识符和span来改善错误。
在下面的代码中,您创建了一个标识符并指向参数的“span”(基本上是代码中这些参数的原始位置),而不是硬编码Trait。代码的其余部分几乎没有变化。
字符串
现在,使用以下代码,也是基于您的示例:
型
你会得到这个错误:
型
对我来说更有帮助。
vyu0f0g12#
不幸的是,你不能这么做。
Debug
是特殊的,因为它在标准库中,标准库可以使用不稳定的内部特性。它使用#[rustc_on_unimplemented]
来指定自定义错误消息。它看起来像这样:
字符串
你可以为你的特质做一些类似的事情,但这需要你每晚坚持,这是一个没有文档的内部特性。我不建议你那样做。
There is an RFC to allow you to use that in your code,但目前尚未实现。