如何在 Rust 中定义一个公共结构,其中所有字段都是公共的,而不必pub在每个字段前重复修饰符?
一个pub_struct宏将是理想的:
pub_struct! Foo {
a: i32,
b: f64,
// ...
}
Run Code Online (Sandbox Code Playgroud)
这相当于:
pub struct Foo {
pub a: i32,
pub b: f64,
//...
}
Run Code Online (Sandbox Code Playgroud) 运行 rust 单元测试时,使用属性宏 #[should_panic(expect = )] 来断言测试因正确的错误消息而发生恐慌(这意味着它在您希望它发生恐慌的行处发生恐慌,而不是因为不同的错误。
但是,在使用在errors.rs 文件中定义的标准化错误消息的应用程序中,不可能将错误消息的常量作为expect 的参数传递。
这:
pub const ERR_001: &str = "ERR_001 message";
#[test]
#[should_panic(expected = ERR_001)]
fn test_function() {
//test code here
}
Run Code Online (Sandbox Code Playgroud)
产生以下错误:
error: expected unsuffixed literal or identifier, found `ERR_001`
--> staking/src/storage.rs:74:31
|
74 | #[should_panic(expected = ERR_001)]
|
Run Code Online (Sandbox Code Playgroud)
有没有办法将常量或变量传递给 #[should_panic(expected = )] 宏?或者是否有必要总是写消息而不是?
我在箱子里重复使用宏时遇到了麻烦.
如果在以下位置定义了宏./src/macros.rs:
#[macro_export]
macro_rules! my_macro {
...
}
Run Code Online (Sandbox Code Playgroud)
用于./src/lib.rs:
#[macro_use]
pub mod macros;
Run Code Online (Sandbox Code Playgroud)
我看不到这个宏./src/submod/lib.rs:
my_macro!(...);
Run Code Online (Sandbox Code Playgroud)
它会产生错误消息error: macro undefined: 'my_macro!'.
有没有办法在这个子模块中导入这个宏submod?
我需要创建一个宏派生,其中名称是函数名称的一部分。(这段代码不起作用,只是为了说明问题)
fn impl_logic(ast: &syn::DeriveInput) -> TokenStream {
let name:&syn::Ident = &ast.ident;
let gen = quote! {
pub fn #name_logic() -> Arc<Mutex<UiAplicacion>> {
...
}
};
gen.into()
}
Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?
我找到了以下解决方案来创建一个宏,该宏定义一个函数,如果枚举与变体匹配,该函数将返回 true:
macro_rules! is_variant {
($name: ident, $enum_type: ty, $enum_pattern: pat) => {
fn $name(value: &$enum_type) -> bool {
matches!(value, $enum_pattern)
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
enum TestEnum {
A,
B(),
C(i32, i32),
}
is_variant!(is_a, TestEnum, TestEnum::A);
is_variant!(is_b, TestEnum, TestEnum::B());
is_variant!(is_c, TestEnum, TestEnum::C(_, _));
assert_eq!(is_a(&TestEnum::A), true);
assert_eq!(is_a(&TestEnum::B()), false);
assert_eq!(is_a(&TestEnum::C(1, 1)), false);
Run Code Online (Sandbox Code Playgroud)
有没有办法定义这个宏,以避免为变体数据提供占位符?
换句话说,更改宏以便能够像这样使用它:
is_variant!(is_a, TestEnum, TestEnum::A);
is_variant!(is_a, TestEnum, TestEnum::B);
is_variant!(is_a, TestEnum, TestEnum::C);
Run Code Online (Sandbox Code Playgroud)
使用(如仅按变体而不是值比较枚举std::mem::discriminant中所述)没有帮助,因为它只能用于比较两个枚举实例。在这种情况下,只有一个对象和变体标识符。它还提到了匹配,但如果变体没有数据,则不起作用。TestEnum::A(..)
我想写一个打印"OK"然后在方法中返回self的宏.这是我的第一个宏,所以我尝试了这个,认为它只会像文本替换一样,但它失败了:
macro_rules! print_ok_and_return_self {
() => {
println!("OK");
self
}
}
fn main() {
let a = A{};
a.a().a();
}
struct A {}
impl A {
fn a(self) -> Self {
print_ok_and_return_self!()
}
}
Run Code Online (Sandbox Code Playgroud)
错误:
error: macro expansion ignores token `self` and any following
--> src/main.rs:4:13
|
4 | self
| ^^^^
|
note: caused by the macro expansion here; the usage of `print_ok_and_return_self!` is likely invalid in expression context
--> src/main.rs:17:13
|
17| print_ok_and_return_self!()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
快速查看文档后,我知道这不仅仅是文本替换,但我仍然不知道如何使其工作.
我正在使用proc_macro和设计自定义HTML语法分析器syn.一个样品:
#[derive(Debug)]
struct BlockElement {
stag: Ident,
child: Vec<Element>,
ctag: Ident
}
impl Synom for BlockElement {
named!(parse -> Self, do_parse!(
punct!(<) >>
stag: syn!(Ident) >>
punct!(>) >>
child: syn!(ElementList) >>
punct!(<) >>
punct!(/) >>
ctag: syn!(Ident) >>
punct!(>) >>
(BlockElement { stag, child: child.inner, ctag })
));
}
Run Code Online (Sandbox Code Playgroud)
虽然我知道Span在解析之后如何使用错误,我无法在解析过程中弄清楚如何使用错误.它只是出错了failed to parse anything.如何确定解析失败的位置并给出适当的错误?
我正在尝试实现这样的(简化):
macro_rules! atest {
($closure:tt) => {
let x = 5;
println!("Result is {}", $closure())
};
}
fn main() {
//let x = 50;
atest!((|| 5 + x));
}
Run Code Online (Sandbox Code Playgroud)
它不起作用,因为atest在宏评估之前编译器会考虑宏的参数:
error[E0425]: cannot find value `x` in this scope
--> src/main.rs:10:20
|
10 | atest!((|| 5 + x));
| ^ not found in this scope
Run Code Online (Sandbox Code Playgroud)
是否有可能使这项工作?我的理解是在编译之前扩展了宏.
我开始学习Rust宏,但文档有些限制.哪个好 - 我猜他们是专家.虽然我可以进行基本的代码生成,特性的实现等等,但是一些内置的宏似乎远不止于此,例如各种打印宏,它们检查字符串文字并将其用于代码扩展.
我查看了源代码print!,它调用了另一个名为的宏format_args.不幸的是,这似乎并没有构建在"纯Rust"中,评论只是说"内置编译器".
是否可以编写像print!纯Rust宏一样复杂的东西?如果是这样,它会怎么做?
我实际上对构建"编译时间"感兴趣 - 基本上将某些固定字符串识别为在编译时修复的"关键字".这可能是高性能的(可能)但主要是我只对代码生成感兴趣.
我正在尝试创建一个Vecof TokenStreams,然后在另一个quote!宏中使用该列表:
let list: Vec<_> = some_data
.iter()
.map(
|item| {
quote!{/*...*/}
},
)
.collect();
let generated = quote! {
fn hello_world() {
#(list);*
}
};
Run Code Online (Sandbox Code Playgroud)
但是,在编译时,我收到此错误:
expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`
Run Code Online (Sandbox Code Playgroud)
从宏的文档来看,它似乎TokenStream在插值中应该有效,因为它实现了该ToTokens特征。此外,该列表是 a Vec,它也明确允许在循环插值中使用。
ThereIsNoIteratorInRepetition当我明确使用有效的迭代器时,为什么会收到错误?