如何在Rust宏中通过引用捕获

时间:2018-10-01 09:00:41

标签: macros rust

我有一个宏可以生成match臂:

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,
});

为了能够直接在宏调用中使用表达式,我应该进行哪些更改?

1 个答案:

答案 0 :(得分:2)

使用宏等同于将其扩展的代码替换为其调用位置。这意味着如果宏扩展多次包含and s.sale_id in (SELECT thing FROM new_table) ,则代码将对您多次作为$sort_by传递的表达式求值。如果表达式使用某些变量,则将无效。

这与函数调用的工作方式相反。如果将表达式传递给函数,则将在调用该函数之前对该表达式求值,并且仅将结果传递给该函数。

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

$sort_by

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