Rust宏是否可能与封闭函数的返回类型匹配?
一个例子是类似日志记录和断言宏,它在返回Err
的函数中也返回Result
,而在不返回Result
的函数中则出现紧急情况。要实现此功能,宏应该以某种方式知道封闭函数的返回类型。
我想声明性宏(macro_rules!
)不可能做到这一点,因为它们的匹配类型有限(如The Rust Reference, chapter Macros By Example中所述):项,块,语句,模式,表达式,类型,标识符等,但不是封闭函数的返回类型。
但是也许带有程序宏?
答案 0 :(得分:1)
摘要:不,即使使用程序宏也不容易。而且我实际上认为您不应该写这样的事情,即使有可能。只需让您的宏评估为Result
并让用户处理它即可。
程序性和声明性的Rust宏只能访问其输入流:仅是令牌列表。对于类似函数的宏(通过foo!(...)
调用的宏),输入就是传递给它们的内容。因此,您可以手动传递返回类型:
macro_rules! foo {
(Result $($stuff:tt)*) => { return Err(()); };
($($stuff:tt)*) => { panic!(); };
}
fn returns_result() -> Result<String, ()> {
foo!(Result<(), ()>); // will return `Err`
Ok("hi".into())
}
fn returns_string() -> String {
foo!(String); // will panic
"hi".into()
}
但是我想这不是您想要的:用户将不得不为每次宏调用手动指定返回类型。
以这种方式调用的过程宏也是如此。
我们可以定义一个过程宏,其中函数的返回类型在输入令牌流中吗?是的,最好通过proc-macro属性。如果定义了这样的属性bar
,则可以这样编写:
#[bar]
fn returns_result() -> Result<String, ()> { ... }
您的过程宏将接收整个函数定义作为输入,包括返回类型。 但是您将如何处理这些信息?
您可以根据需要更改整个函数,因此一个想法是在函数中搜索所有foo!()
宏调用,然后根据需要将它们替换为return Err
或panic!()
返回类型。也就是说:通过程序宏对自己的宏执行宏调用步骤。
但是我认为这是一个坏主意,原因有几个。最重要的是,当编译器调用过程宏时,我认为定义不正确。因此,编译器可以在调用过程宏之前尝试调用您的foo!()
宏。
因此,它可以通过过程宏来工作,但不能以典型的方式工作。因此,很黑。
最后,我该怎么做? 让您的宏评估为Result
。然后,用户可以轻松地决定自己要怎么做。如果他们返回Result
,则只需添加?
。如果没有,他们可以自由选择.unwrap()
,expect()
和其他恐慌方式。
我了解您为什么要尝试做自己想做的事情(这对用户来说更容易且舒适),但是我认为这不是一个好主意。它可能归结为“遥远的鬼动作” :您的函数中的宏突然执行的操作取决于该函数的返回类型。这意味着当您进行更改时,函数的整个语义都会发生变化。这听起来像是您可以非常轻松地将自己拍到脚上的东西。这可能也是在Rust中不容易的原因。