Skip to content

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
}