匹配“结构字段语法”中的寿命传递给macro_rules
我已经定义了以下宏,因为我需要经过Serde序列化的许多略有不同的结构。
macro_rules! instantiate {
(
$(#[$struct_meta:meta])*
$struct_name:ident {
$(
$(#[$field_meta:meta])*
$field_name:ident: $field_type:ty = $field_value:expr,
)+
}
) => {{
$(#[$struct_meta])*
struct $struct_name {
$(
$(#[$field_meta])*
$field_name: $field_type,
)*
}
$struct_name {
$($field_name: $field_value,)*
}
}};
}
它应该像这样使用:
instantiate! {
#[derive(serde::Serialize)]
RequestParams {
#[serde(serialize_with="serialize_debug")]
ids: Vec<Base62Uint> = version_ids
.into_iter()
.map(std::fmt::Display::to_string)
.collect(),
}
}
但是,我还有另一种用途:
let (hash, kind) = match hash {
FileHashes {
sha512: Some(hash), ..
} => (hash, "sha512"),
FileHashes {
sha1: Some(hash), ..
} => (hash, "sha1"),
_ => todo!(),
};
instantiate! {
#[derive(serde::Serialize)]
RequestParams {
algorithm: &str = kind,
}
}
我最终遇到了以下错误,这是可以预期的:
error[E0106]: missing lifetime specifier
--> src/endpoints.rs:236:28
|
236 | algorithm: &str = kind,
| ^ expected named lifetime parameter
|
help: consider introducing a named lifetime parameter
|
88 ~ struct $struct_name<'a> {
89 | $(
90 | $(#[$field_meta])*
91 | $field_name: $field_type,
92 | )*
93 | }
...
我希望这个宏为每个$ field_name
创建一个新的生命周期,其中相应的$ field_type
是参考。
这是我尝试过的:
$field_name: $(&$field_life:lifetime)? $field_type,
停下来,因为我意识到这只会捕获输入寿命,这比我想要的不太符合人体工程学,而我最终会在模式中含糊不清,因为它输入可以匹配任何一个&amp; $ field_life:lifetime
部分或$ field_type:ty
。
I have defined the following macro because I need many slightly different structs with Serde serialization.
macro_rules! instantiate {
(
$(#[$struct_meta:meta])*
$struct_name:ident {
$(
$(#[$field_meta:meta])*
$field_name:ident: $field_type:ty = $field_value:expr,
)+
}
) => {{
$(#[$struct_meta])*
struct $struct_name {
$(
$(#[$field_meta])*
$field_name: $field_type,
)*
}
$struct_name {
$($field_name: $field_value,)*
}
}};
}
And it should be used just like this:
instantiate! {
#[derive(serde::Serialize)]
RequestParams {
#[serde(serialize_with="serialize_debug")]
ids: Vec<Base62Uint> = version_ids
.into_iter()
.map(std::fmt::Display::to_string)
.collect(),
}
}
However, I have another use for it:
let (hash, kind) = match hash {
FileHashes {
sha512: Some(hash), ..
} => (hash, "sha512"),
FileHashes {
sha1: Some(hash), ..
} => (hash, "sha1"),
_ => todo!(),
};
instantiate! {
#[derive(serde::Serialize)]
RequestParams {
algorithm: &str = kind,
}
}
I end up with the following error, which was expected:
error[E0106]: missing lifetime specifier
--> src/endpoints.rs:236:28
|
236 | algorithm: &str = kind,
| ^ expected named lifetime parameter
|
help: consider introducing a named lifetime parameter
|
88 ~ struct $struct_name<'a> {
89 | $(
90 | $(#[$field_meta])*
91 | $field_name: $field_type,
92 | )*
93 | }
...
I want this macro to create a new lifetime for every $field_name
, where the corresponding $field_type
is a reference.
Here is what I have attempted:
$field_name: $(&$field_life:lifetime)? $field_type,
And stopped because I realized that would only capture the input lifetimes, which is less ergonomic than what I want, and I would end up with an ambiguity in the pattern because it input would be able to match either the &$field_life:lifetime
portion or the $field_type:ty
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为您的最低可再现示例是
,您的第二个例子是,宏是相同的:
解决方案#1-廉价的解决方案而无需捕获生命寿命的
解决方案#2-捕获寿命
I assume that your minimal reproducible example is
and your second example is, with the macro being identical:
Solution #1 - the cheap solution without capturing lifetimes
Solution #2 - capturing lifetimes
macro_rules!
无法生成寿命,其原因与他们无法生成标识符的原因相同( Rust Macro可以创建新的标识符?),因为它们无法(没有帮助)生成新的令牌。您必须使用程序宏。您可以使用现有的程序宏来允许您生成令牌,例如 @dtolnay的 /code> 板条箱,但这会引起另一个问题:您如何知道将一生放在哪里?您可以(部分地,因为您无法识别所有需要生命的类型)来解决这一问题,通过tt-munnering和识别需要生命的类型(例如参考),但这将使您的宏观真正的 Complex比PROC宏。我不建议这样做。
macro_rules!
cannot generate lifetimes, for the same reasons they cannot generate identifiers (Can a Rust macro create new identifiers?), because they cannot (without help) generate new token. You have to use a procedural macro for that.You can use existing procedural macros that allow you to generate tokens, for example @dtolnay's
seq-macro
crate, but it will raise another problem: how do you know where to put the lifetime? You can (partially, because you cannot identify all types requiring lifetimes) solve that by tt-munching and identifying types that require lifetimes (for example references), but this will make your macro really complex, even more than a proc macro. I do not recommend doing that.