Macros 如何消除虚假警告;指定的值永远不会被读取;在宏中?
我是新手,正在学习编写自己的宏。这个宏应该填充我的结构Macros 如何消除虚假警告;指定的值永远不会被读取;在宏中?,macros,rust,Macros,Rust,我是新手,正在学习编写自己的宏。这个宏应该填充我的结构MatrixXf就像宏vec不适用于Vec 我是这样用的: let mat = mat![1.0, 2.0, 3.0; 4.0, 5.0, 6.0]; 一切正常,但编译器向我显示以下警告: 7:23警告:分配给的值是第一行收集的永远不会被读取,#[警告(未使用的分配)]默认打开 :7是第一行收集的值=真;cols=内部_cols;}行+=1;)* 也许我误解了什么,但在检查是否访问了第一行时,我确实使用了is\u first\u row\u
MatrixXf
就像宏vec代码>不适用于Vec
我是这样用的:
let mat = mat![1.0, 2.0, 3.0; 4.0, 5.0, 6.0];
一切正常,但编译器向我显示以下警告:
7:23警告:分配给的值是第一行收集的
永远不会被读取,#[警告(未使用的分配)]默认打开
:7是第一行收集的值=真;cols=内部_cols;}行+=1;)*
也许我误解了什么,但在检查是否访问了第一行时,我确实使用了is\u first\u row\u collected
。是否可以重写代码以避免此警告 是的,这里好像有什么东西掉了。如果您自己手动展开代码,是否仍会收到警告?或者只是当它在宏中时?警告是真实的;让我们使用这个修改后的示例,它不依赖于您在问题中未提供的结构:
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
这是一个又大又难看的代码块,因此我将把它精简到相关部分:
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;
}
}
因此,实际上,您指定的值永远不会被读取。当然,作为一个人,你可以看到这个特定的流不应该发生,也许你可以请求对编译器进行增强以跟踪它
理想情况下,您应该重新编写宏,以避免出现潜在问题。如果无法重新编写宏,则可以允许该警告。不幸的是,除了fn
或mod
之外,我不知道如何在任何东西上添加#[allow(unused#u assignments)]
声明,因此看起来您无论如何都必须对宏进行一些更改。而不是使用布尔变量,您可以在选项中包装cols
,以明确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
}}
}
在这个版本的宏中,我添加了另一个规则,在没有参数时构造一个空矩阵,我移动了分号的位置,这样当只有一行时就不需要尾随分号。不用担心你的英语!我完全理解你的要求。我在编辑中修改了一两个小东西。谢谢你们的回答。我写了一些类似于我的宏的东西,但是用for循环代替了$()*(我不知道如何在宏之外实现它)。没有任何警告。对我来说听起来像个虫子。rustc里的虫子?(我的版本是1.2.0)是的!我不记得在追踪器中看到过一个,但是如果你能得到一个测试用例,我想你应该把它归档。(顺便说一句,1.3也发布了)哦,新版本,不错)Rustc仍然向我显示警告,所以我将尝试发送错误报告“你在问题中没有提供的结构”,我认为这种结构在这个问题上无关紧要。我将在进一步的问题中提供结构描述。谢谢你的解释。@Dark_Daiver你是对的,在这种情况下这无关紧要,但最好的问题是那些可以粘贴进去并显示错误的问题。这被称为一个。这样人们就不必修改你的示例代码以使其可运行,可能会修改它并得到不同的错误(以及错误的原因),做出无用的回答并浪费时间。我同意你的看法。尽可能小的例子来描述这个问题是很重要的。谢谢你们的回答。你们的帖子完全回答了我的问题,但谢普马斯特的帖子告诉我,我对虚假警告的理解是错误的。所以我不能决定我应该把哪个帖子作为答案。
//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
}}
}