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?

3 Answers

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]) } 
0

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); } 
0

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.