在 [false, true] 中迭代的最有效方法是什么?

What is the most efficient way to iterate in [false, true]?

我有一个需要 3 个布尔值的函数 foo,我想用每个布尔值组合得到这个函数的结果。

我是这样做的:

fn foo(b1: bool, b2: bool, b3: bool) -> bool {
    b1 && b2 || !b3
}

fn main() {
    for b1 in vec![false, true] {
        for b2 in vec![false, true] {
            for b3 in vec![false, true] {
                println!("{} {} {} -> {}", b1, b2, b3, foo(b1, b2, b3));
            }
        }
    }
}

有没有比创建向量然后遍历它更直接/更短的方法?

有没有一种方法可以使用宏或可变函数来完成,以便编译器只遍历每个案例而不进行迭代?

理想情况下,您应该写 for b1 in [false, true],但那是 not yet possible

即使没有它,您也可以比分配和使用 Vec 做得更好 - 例如,您可以遍历数组切片:

for &b1 in &[false, true] {
    for &b2 in &[false, true] {
        for &b3 in &[false, true] {
            ...

请注意,该模式指定了一个引用(取消引用 匹配值)因为遍历 T 的一片不会产生实际的 T值,但 &T 引用驻留在切片中的值。

要直接迭代固定的少量值,您可以使用 std::iter::once()chain():

for b1 in std::iter::once(false).chain(std::iter::once(true)) {
    ...

上面的内容可以通过(误)使用 Option 来稍微缩短,这也是可迭代的:

for b1 in Some(false).into_iter().chain(Some(true)) {
    ...

至少您可以使用数组而不是向量,从而节省动态分配:

fn foo(b1: bool, b2: bool, b3: bool) -> bool {
  b1 && b2 || !b3
}

fn main() {
  for b1 in &[false, true] {
    for b2 in &[false, true] {
      for b3 in &[false, true] {
        println!("{} {} {} -> {}", 
                 b1, b2, b3,
                 foo(*b1, *b2, *b3));
      }
    }
  }
}

然后你可以使用 itertools::iproduct!:

来节省循环嵌套
use itertools::iproduct; // 0.9.0

fn foo(b1: bool, b2: bool, b3: bool) -> bool {
  b1 && b2 || !b3
}

fn main() {
  for (&b1, &b2, &b3) in iproduct!(&[false, true], &[false, true], &[false, true]) {
    println!("{} {} {} -> {}", 
             b1, b2, b3,
             foo(b1, b2, b3));
  }
}

(playground)

您可以使用 itertools crate and then use the iproduct!() 宏。

use itertools::iproduct;

fn main() {
    const FT: &[bool; 2] = &[false, true];

    for (&b1, &b2, &b3) in iproduct!(FT, FT, FT) {
        println!("{} {} {} -> {}", b1, b2, b3, foo(b1, b2, b3));
    }
}

不是说它“更高效”,而是写起来更短。

没有必要把事情复杂化。你可以这样做:

fn main() {
    for i in 0..=0b111 {
        let a = (i & 1) == 1;
        let b = (i >> 1 & 1) == 1;
        let c = (i >> 2 & 1) == 1;
        println!("{} {} {} -> {}", a, b, c, foo(a, b, c));
    }
}