我是Rust的新手,正在学习编写自己的宏。这个宏应该填充我的结构MatrixXf
,就像宏vec!
对Vec<T>
所做的那样。
//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警告:永远不会读取分配给
is_first_row_collected
的值,默认情况下#[warn(unused_assignments)]开启 :7 is_first_row_collected = true; cols = inner_cols; } rows + = 1; )*
也许我误解了一些东西,但在检查第一行是否被访问时我确实使用了is_first_row_collected
。是否可以重写我的代码以避免此警告?
答案 0 :(得分:4)
您可以在_socker.hasListeners('account/connected');
中包含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
}}
}
在这个版本的宏中,我添加了另一个规则,当没有参数时构造一个空矩阵,并且我移动了分号的位置,这样当你只有一行时就不需要一个尾随的分号。 / p>
答案 1 :(得分:2)
警告是真实的;让我们使用这个不依赖于您在问题中未提供的结构的修改示例:
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;
}
}
因此,确实,您分配的值永远不会被读取。当然,作为一个人,你可以看到不应该发生特定的流程,也许你可以请求增强编译器来跟踪它。
理想情况下,您将修改宏以避免潜在的问题。 Francis Gagné shows a great way of doing that。如果您无法重做宏,则可以允许该警告。遗憾的是,除了#[allow(unused_assignments)]
或fn
之外,我不知道有什么方法可以添加mod
声明,因此您似乎必须对无论如何。宏。
答案 2 :(得分:1)
是的,看起来像棉绒里的东西就在这里。如果您自己手动扩展代码,是否仍会收到警告?或者它只是在宏观中?