有什么方法可以将迭代器解包到元组中吗?

Is there any way to unpack an iterator into a tuple?

有什么方法可以完成类似下面的事情:

let v = vec![1, 2, 3];
let (a, b) = v.iter().take(2);

最后是 a = 1b = 2

我知道我可以只使用向量,但我想要命名变量。

这可能并不完全符合您的要求,但我想您无论如何都不想将任意大的向量转换为元组。如果您只想将一个向量的前几个元素提取到一个元组中,您可以使用 切片模式匹配 :

fn main() {
    let v = vec![1, 2, 3];
    let (a, b) = match &v[..] {
        &[first, second, ..] => (first, second),
        _ => unreachable!(),
    };
    assert_eq!((a, b), (1, 2));
}

itertools crate 有类似 tuples and next_tuple 的方法可以帮助解决这个问题。

use itertools::Itertools; // 0.9.0

fn main() {
    let v = vec![1, 2, 3];
    let (a, b) = v.iter().next_tuple().unwrap();

    assert_eq!(a, &1);
    assert_eq!(b, &2);
}

我写了这个将 Vec 转换为元组的丑陋的递归宏,因为我想了解一些有关宏的知识。

macro_rules! tuplet {
    { ($y:ident $(, $x:ident)*) = $v:expr } => {
        let ($y, $($x),*) = tuplet!($v ; 1 ; ($($x),*) ; ($v[0]) );
    };
    { $v:expr ; $j:expr ; ($y:ident $(, $x:ident)*) ; ($($a:expr),*) } => {
        tuplet!( $v ; $j+1 ; ($($x),*) ; ($($a),*,$v[$j]) )
    };
    { $v:expr ; $j:expr ; () ; $accu:expr } => {
        $accu
    }
}

我是新手,可能不太擅长,所以很可能有更好的方法来做到这一点。这只是一个概念证明。它允许你写:

fn main() {
    let v = vec![1, 2, 3];
    tuplet!((a, b, c) = v);

    assert_eq!(a, 1);
    assert_eq!(b, 2);
    assert_eq!(c, 3);
}

在该宏定义的某处,您可以找到 $v[$j] 部分,如果您想将其用于迭代器,可以将其替换为 $v.nth($j)

gcp走在正确的轨道上;他的回答对我来说似乎是正确的。

不过,我要举一个更有说服力的例子,因为 OP 在评论中似乎想知道他的要求是否值得 ("I can't think of a good enough reason for this functionality to be possible.")。查看下面的 Person::from_csv 函数:

use itertools::Itertools;

#[derive(Debug)]
struct Person<'a> {
    first: &'a str,
    last:  &'a str,
}

impl<'a> Person<'a> {
    // Create a Person from a str of form "last,first".
    fn from_csv(s: &'a str) -> Option<Self> {
        s.split(',').collect_tuple().map(
            |(last, first)| Person { first, last }
        )
    }
}

fn main() {
    dbg!(Person::from_csv("Doe"));          // None
    dbg!(Person::from_csv("Doe,John"));     // Some(...)
    dbg!(Person::from_csv("Doe,John,foo")); // None
}

它接受由split生成的迭代器并将结果收集到一个元组中,以便我们可以匹配和解构它。如果逗号太多或太少,您将无法获得匹配的元组。这段代码很干净,因为 collect_tuple 让我们可以使用模式匹配和解构。

这里是in the playground