将 Ifs 向上推,将 Fors 向下推

A short note on two related rules of thumb.

关于两个相关经验法则的简短说明。

If there’s an if condition inside a function, consider if it could be moved to the caller instead:

如果函数内部有一个if条件,考虑是否可以将其移动到调用者那里:


fn frobnicate(walrus: Walrus) {
 ...
} fn frobnicate(walrus: Option<Walrus>) {
 let walrus = match walrus {
 Some(it) => it,
 None => return,
 };
 ...
}

As in the example above, this often comes up with preconditions: a function might check precondition inside and “do nothing” if it doesn’t hold, or it could push the task of precondition checking to its caller, and enforce via types (or an assert) that the precondition holds. With preconditions especially, “pushing up” can become viral, and result in fewer checks overall, which is one motivation for this rule of thumb.

如上面的例子所示,这通常与前置条件有关:一个函数可能在内部检查前置条件,如果不满足则“什么也不做”,或者它可以将前置条件检查的任务推给调用者,并通过类型(或断言)来强制前置条件成立。尤其是在前置条件方面,“向上推”可能会变得具有传染性,导致总体检查减少,这也是这个经验法则的一个动机。

Another motivation is that control flow and ifs are complicated, and are a source of bugs. By pushing ifs up, you often end up centralizing control flow in a single function, which has a complex branching logic, but all the actual work is delegated to straight line subroutines.

另一个动机是控制流和if很复杂,并且是错误的来源。通过将if上推,你通常会将控制流集中在一个单一的函数中,该函数具有复杂的分支逻辑,但所有实际工作都委托给直线子例程。

If you have complex control flow, better to fit it on a screen in a single function, rather than spread throughout the file. What’s more, with all the flow in one place it often is possible to notice redundancies and dead conditions. Compare:

如果你有复杂的控制流,最好将其适配到一个屏幕上的单个函数中,而不是分散在整个文件中。更重要的是,所有流在一个地方时,通常可以注意到冗余和死条件。比较:

fn f() {
 if foo && bar {
 if foo {  } else {  }
 }
} fn g() {
 if foo && bar {
 h()
 }
} fn h() {
 if foo {  } else {  }
}

For f, it’s much easier to notice a dead branch than for a combination of g and h!

对于 f,发现一个死分支要比发现 gh 的组合容易得多!

A related pattern here is what I call “dissolving enum” refactor. Sometimes, the code ends up looking like this:

这里一个相关的模式是我称之为“溶解枚举”的重构。有时,代码最终看起来像这样:

enum E {
 Foo(i32),
 Bar(String),
} fn main() {
 let e = f();
 g(...
开通本站会员,查看完整译文。

Accueil - Wiki
Copyright © 2011-2025 iteam. Current version is 2.143.0. UTC+08:00, 2025-05-19 21:26
浙ICP备14020137号-1 $Carte des visiteurs$