如何消除宏中的虚假警告 "value assigned is never read"?

How do I eliminate the spurious warning "value assigned is never read" in a macro?

我是 Rust 新手,正在学习编写自己的宏。这个宏应该像宏 vec!Vec<T>.

所做的那样填充我的结构 MatrixXf
//fills matrix with matlab like syntax
macro_rules! mat {
    [ $($( $x: expr ),*);* ] => {{
        let mut tmp_vec = Vec::new();
        let mut rows = 0;
        let mut cols = 0;
        let mut is_first_row_collected = false;
        $(
            let mut inner_cols = 0;
            $(
                tmp_vec.push($x);
                inner_cols += 1;
            )*
            if is_first_row_collected {//if we read first row we can check that other rows have same length
                assert!(inner_cols == cols);
            } else {
                is_first_row_collected = true;
                cols = inner_cols;
            }
            rows += 1;
        )*
        MatrixXf::construct(tmp_vec, rows, cols)//fills MatrixXf fields
    }}
}

我是这样使用的:

let mat = mat![1.0, 2.0, 3.0; 4.0, 5.0, 6.0];

一切正常,但编译器显示以下警告:

7:23 warning: value assigned to is_first_row_collected is never read, #[warn(unused_assignments)] on by default :7 is_first_row_collected = true ; cols = inner_cols ; } rows += 1 ; ) *

也许我误解了什么,但我在检查是否访问了第一行时确实使用了 is_first_row_collected。是否可以重写我的代码以避免出现此警告?

是的,这看起来 lint 中的某些内容已关闭。如果你自己手动展开代码,你还会得到警告吗?还是只是在宏中?

警告是真实的;让我们使用这个修改后的示例,它不依赖于您在问题中未提供的结构:

macro_rules! mat {
    [ $($( $x: expr ),*);* ] => {{
        let mut tmp_vec = Vec::new();
        let mut rows = 0;
        let mut cols = 0;
        let mut is_first_row_collected = false;
        $(
            let mut inner_cols = 0;
            $(
                tmp_vec.push($x);
                inner_cols += 1;
            )*
            if is_first_row_collected {//if we read first row we can check that other rows have same length
                assert!(inner_cols == cols);
            } else {
                is_first_row_collected = true;
                cols = inner_cols;
            }
            rows += 1;
        )*
        (tmp_vec, rows, cols)
    }}
}

fn main() {
    let _mat = mat![1.0, 2.0, 3.0; 4.0, 5.0, 6.0];
}

然后我们可以使用编译器查看扩展版本是什么:

rustc -Z unstable-options --pretty expanded example.rs

这是一大堆丑陋的代码,所以我将 trim 分解为相关部分:

fn main() {
    let mut is_first_row_collected = false;

    if is_first_row_collected {
        // removed
    } else {
        is_first_row_collected = true;
    }

    if is_first_row_collected {
        // removed
    } else {
        is_first_row_collected = true;
    }
}

所以,确实,您分配的值从未被读取。当然,作为人类,您可以看到该特定流程不应该发生,也许您可​​以请求增强编译器来跟踪它。

理想情况下,您应该修改宏以消除根本问题。 。如果您无法修改宏,则可以允许该警告。不幸的是,除了 fnmod,我不知道有什么方法可以添加 #[allow(unused_assignments)] 声明,所以看起来你必须对你的无论如何宏。

您可以将 cols 包装在 Option 中,而不是使用布尔变量,以明确 cols 在您阅读第一行之前没有有效值。

//fills matrix with matlab like syntax
macro_rules! mat {
    [ $($( $x: expr ),*);* ] => {{
        let mut tmp_vec = Vec::new();
        let mut rows = 0;
        let mut cols = None;
        $(
            let mut inner_cols = 0;
            $(
                tmp_vec.push($x);
                inner_cols += 1;
            )*
            if let Some(cols) = cols {//if we read first row we can check that other rows have same length
                assert!(inner_cols == cols);
            } else {
                cols = Some(inner_cols);
            }
            rows += 1;
        )*
        MatrixXf::construct(tmp_vec, rows, cols.unwrap_or(0))//fills MatrixXf fields
    }}
}

另一种选择是通过在宏模式中分隔第一行和后续行来不同地处理它们。这样,我们就可以完全避免该标志,因为当我们处理以下行时,我们已经知道列数。

//fills matrix with matlab like syntax
macro_rules! mat {
    [] => { MatrixXf::construct(Vec::new(), 0, 0) };
    [ $( $x: expr ),* $(; $( $y: expr ),*)* ] => {{
        let mut tmp_vec = Vec::new();
        let mut rows = 0;
        let mut inner_cols = 0;
        $(
            tmp_vec.push($x);
            inner_cols += 1;
        )*
        let cols = inner_cols; // remember how many columns the first row has
        rows += 1;
        $(
            inner_cols = 0;
            $(
                tmp_vec.push($y);
                inner_cols += 1;
            )*
            assert!(inner_cols == cols); // check that the following rows have as many columns as the first row
            rows += 1;
        )*
        MatrixXf::construct(tmp_vec, rows, cols)//fills MatrixXf fields
    }}
}

在这个版本的宏中,我添加了另一个规则来在没有参数时构造一个空矩阵,并且我移动了分号的位置,这样当只有一行时就不需要尾随分号了.