G.CTF.02 在 Match 分支的 Guard 语句中不要使用带有副作用的条 件表达式
【级别】 建议
【描述】
在 match 分支中, 匹配几次就会执行 Guard 几次。 Guard 的条件表达式不应该携带副作用。
【说明】
副作用是指对执行状态产生影响,包括:修改对象、修改文件等。在某些情况下副作用会给程序带来不 必要的麻烦,其产生的错误十分难以查找,并降低程序的可读性。
【反例】
Rust
use std::cell::Cell;
fn main() {
let i: Cell<i32> = Cell::new(0);
let opt = Some(1);
// 不符合:代码最终会输出两次 "add 1"
match opt {
// 这个条件表达式带有副作用:打印并修改了变量 i 内部的值,因为匹配两次,所以会执行两次
Some(1) | Some(_) if condition(&i) => {}
_ => {}
}
assert_eq!(i.get(), 2);
}
// 带有副作用,匹配时多次执行可能会出现预想不到的逻辑问题
fn condition(i: &Cell<i32>) -> bool {
println!("add 1");
i.set(i.get() + 1); // 如果函数被执行两次,这里也会被设置两次
false
}
【正例】
Rust
use std::cell::Cell;
fn main() {
let i: Cell<i32> = Cell::new(0); let opt = Some(1);
// 符合:代码最终输出一次 "add 1"
match opt {
// 注意有副作用的函数被移动到了Guard语句之后调用以作判断
Some(1) => if condition(&i) {}
Some(_) => if condition(&i)
{} _ => {}
}
assert_eq!(i.get(), 1);
}
// 带有副作用,匹配时多次执行可能会出现预想不到的逻辑问题
fn condition(i: &Cell<i32>) -> bool { println!("add 1");
i.set(i.get() + 1); // 如果函数被执行两次,这里也会被设置两次
false
}