有没有办法完成以下内容:
let v = vec![1, 2, 3];
let (a, b) = v.iter().take(2);
最后是a = 1
和b = 2
?
我知道我可以使用矢量,但我想命名变量。
答案 0 :(得分:11)
这可能不是你要求的,但我想你很少想要将任意大的矢量转换为元组。如果您只想将矢量的前几个元素提取到元组中,则可以使用夜间实验功能切片模式匹配来实现:
#![feature(slice_patterns)]
fn main() {
let v = vec![1, 2, 3];
let (a, b) = match &v[..] {
&[first, second, ref _tail..] => (first, second),
_ => unreachable!(),
};
assert_eq!((a, b), (1, 2));
}
答案 1 :(得分:8)
itertools crate有tuples
和next_tuple
等方法可以帮助解决这个问题。
extern crate itertools;
use itertools::Itertools;
fn main() {
let v = vec![1, 2, 3];
let (a, b) = v.iter().next_tuple().unwrap();
assert_eq!(a, &1);
assert_eq!(b, &2);
}
答案 2 :(得分:3)
我编写了这个丑陋的递归宏,它将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)
替换它。
答案 3 :(得分:1)
gcp处于正确的轨道;他的回答对我来说似乎是正确的。
不过,我将提供一个更具说服力的示例,因为OP似乎在想知道他要求的内容是否值得(“我想不出足够充分的理由将此功能作为可能。”)。请查看下面的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
产生的Iterator并将结果收集到一个元组中,以便我们可以对其进行匹配和解构。如果逗号太多或太少,则不会得到匹配的元组。这段代码很干净,因为collect_tuple
使我们可以使用模式匹配和解构。