Here's an example that splits a string and parses each item, putting it into a tuple whose size is known at compile time.
use std::str::FromStr;
fn main() {
let some_str = "123,321,312";
let num_pair_str = some_str.split(',').collect::<Vec<&str>>();
if num_pair_str.len() == 3 {
let num_pair: (i32, i32, i32) = (
i32::from_str(num_pair_str[0]).expect("failed to parse number"),
i32::from_str(num_pair_str[1]).expect("failed to parse number"),
i32::from_str(num_pair_str[2]).expect("failed to parse number"),
);
println!("Tuple {:?}", num_pair);
}
}
Is there a way to avoid repetition parsing the numbers?
This is an example of what it might look like if Rust supported Python-like comprehensions:
let num_pair: (i32, i32, i32) = (
i32::from_str(num_pair_str[i]).expect("failed to parse number")
for i in 0..3
);
Is it possible to declare the tuple in a way that expands the vector?
What is Vector of Tuple? A tuple is an object that can hold a number of elements and a vector containing multiple number of such tuple is called a vector of tuple. The elements can be of different data types. The elements of tuples are initialized as arguments in order in which they will be accessed.
This article focuses on how to create a 2D vector of tuples in C++. A 2D vector of tuples or vector of vectors of tuples is a vector in which each element is a vector of tuples itself. Although a tuple may contain any number of elements for simplicity, a tuple of three elements is considered.
Class template std::tuple is a fixed-size collection of heterogeneous values. It is a generalization of std::pair. If std::is_trivially_destructible<Ti>::value is true for every Ti in Types , the destructor of tuple is trivial.
You can't use Python-like list comprehension, as Rust doesn't have it. The closest thing is to do it explicitly via another iterator. You can't directly collect into a tuple, so you need another explicit step to convert the vector:
use std::str::FromStr;
fn main() {
let some_str = "123,321,312";
let num_pair_str = some_str.split(',').collect::<Vec<_>>();
if num_pair_str.len() == 3 {
let v = num_pair_str.iter().map(|s| i32::from_str(s).expect("failed to parse number"))
.collect::<Vec<_>>();
let num_pair: (i32, i32, i32) = (v[0], v[1], v[2]);
println!("Tuple {:?}", num_pair);
}
}
If you want to avoid the intermediate vectors you can do something like the following:
use std::str::FromStr;
fn main() {
let some_str = "123,321,312";
let it0 = some_str.split(',');
if it0.clone().count() == 3 {
let mut it = it0.map(|s| i32::from_str(s).expect("failed to parse number"));
let num_pair: (i32, i32, i32) =
(it.next().unwrap(), it.next().unwrap(), it.next().unwrap());
println!("Tuple {:?}", num_pair);
}
}
You can declare a trait with a method similar to Iterator::collect
and implement it to collect to various tuples sizes:
fn main() {
// Example with some simplifications
// Note that there is no extra allocation
let num_pair: (i32, i32, i32) = "123,321,312"
.split(',')
.map(|s| s.parse().expect("an i32"))
.try_collect()
.expect("a 3-tuple of i32");
assert_eq!(num_pair, (123, 321, 312));
}
trait TryCollect<T> {
fn try_collect(&mut self) -> Option<T>;
}
macro_rules! impl_try_collect_tuple {
() => { };
($A:ident $($I:ident)*) => {
impl_try_collect_tuple!($($I)*);
impl<$A: Iterator> TryCollect<($A::Item, $($I::Item),*)> for $A {
fn try_collect(&mut self) -> Option<($A::Item, $($I::Item),*)> {
let r = (try_opt!(self.next()),
// hack: we need to use $I in the expasion
$({ let a: $I::Item = try_opt!(self.next()); a}),* );
Some(r)
}
}
}
}
macro_rules! try_opt {
($e:expr) => (match $e { Some(e) => e, None => return None })
}
// implement TryCollect<T> where T is a tuple with size 1, 2, .., 10
impl_try_collect_tuple!(A A A A A A A A A A);
Other examples:
fn main() {
let mut iter = (0..7).into_iter();
let (a, b, c) = iter.try_collect().unwrap();
assert_eq!((a, b, c), (0, 1, 2));
let (d, e) = iter.try_collect().unwrap();
assert_eq!((d, e), (3, 4));
let (f,) = iter.try_collect().unwrap();
assert_eq!(f, 5);
let a: Option<(u32, u32)> = iter.try_collect();
assert_eq!(None, a);
}
EDIT: A simple one-liner solution: collect_tuple of the popular itertools
crate.
let iter = 1..3;
let (x, y) = iter.collect_tuple().unwrap(); // yeah!
Original answer
If you want better IDE type hinting, macros may not be a perfect solution. Here is my attempt:
fn tuple1<T>(a: &[T]) -> (&T) { (&a[0]) }
fn tuple2<T>(a: &[T]) -> (&T, &T) { (&a[0], &a[1]) }
fn tuple3<T>(a: &[T]) -> (&T, &T, &T) { (&a[0], &a[1], &a[2]) }
fn tuple4<T>(a: &[T]) -> (&T, &T, &T, &T) { (&a[0], &a[1], &a[2], &a[3]) }
fn tuple5<T>(a: &[T]) -> (&T, &T, &T, &T, &T) { (&a[0], &a[1], &a[2], &a[3], &a[4]) }
fn tuple6<T>(a: &[T]) -> (&T, &T, &T, &T, &T, &T) { (&a[0], &a[1], &a[2], &a[3], &a[4], &a[5]) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With