【问题标题】:How to capture by reference in rust macro如何在 rust 宏中通过引用捕获
【发布时间】:2018-10-01 09:00:41
【问题描述】:

我有一个宏来生成matcharms:

macro_rules! sort_by {
    ( $query:ident, $sort_by:expr, { $( $name:pat => $column:path,)+ } ) => {
        match $sort_by.column {
            $(
                $name => if $sort_by.descending {
                    $query = $query.order_by($column.desc());
                } else {
                    $query = $query.order_by($column.asc());
                },
            )+
        }
    }
}

我想这样称呼它:

sort_by!(query, sort_by.unwrap_or(Sort::desc("id")), {
    "id" => table::id,
    "customerName" => table::customer_name,
});

但我收到一个错误:

sort_by!(query, &sort_by.unwrap_or(Sort::desc("id")), {
                ^^^^^^^ value moved here in previous iteration of loop

所以我必须这样称呼它:

let sort = sort_by.unwrap_or(Sort::desc("id"));
sort_by!(query, &sort, {
    "id" => table::id,
    "customerName" => table::customer_name,
});

我应该改变什么才能直接在宏调用中使用表达式?

【问题讨论】:

  • 错误信息看起来像是在loop 中使用宏,这似乎是问题的根源。
  • 第一个错误是:failed to resolve. Use of undeclared type or module 'Sort'。我认为您的帖子中缺少代码。 play.rust-lang.org/…

标签: macros rust


【解决方案1】:

使用宏相当于将其展开的代码替换到其调用站点中。这意味着如果宏扩展包含$sort_by 多次,代码将多次评估您作为$sort_by 传入的表达式。如果表达式消耗了一些变量,这将是无效的。

这与函数调用的工作方式相反。如果您将表达式传递给函数,则会在调用函数之前对其进行评估,并且仅将结果传递给函数。

如果这是您的问题的根源,您可以通过将 $sort_by 分配给宏扩展内的局部变量来修复它,并且随后仅访问该局部变量:

macro_rules! sort_by {
    ($query:ident, $sort_by:expr, { $($name:pat => $column:path,)+ }) => {
        let sort_by = $sort_by;
        match sort_by.column {
            $(
                $name => if sort_by.descending {
                    $query = $query.order_by($column.desc());
                } else {
                    $query = $query.order_by($column.asc());
                },
            )+
        }
    }
}

(请注意,我无法对此进行测试,因为您的示例不完整。)

【讨论】:

  • 在我的情况下应该是let sort_by = &$sort_by;。谢谢!
猜你喜欢
  • 1970-01-01
  • 2022-01-17
  • 2021-04-07
  • 2021-11-09
  • 2016-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多