有什么方法可以将迭代器解包到元组中吗?
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 = 1
和 b = 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
让我们可以使用模式匹配和解构。
有什么方法可以完成类似下面的事情:
let v = vec![1, 2, 3];
let (a, b) = v.iter().take(2);
最后是 a = 1
和 b = 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
让我们可以使用模式匹配和解构。