这是一个分割字符串并解析每个项目的示例,将其放入一个元组,其大小在编译时是已知的。
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);
}
}
有没有办法避免重复解析数字?
这是一个示例,如果Rust支持类似Python的理解,它可能会是什么样子:
let num_pair: (i32, i32, i32) = (
i32::from_str(num_pair_str[i]).expect("failed to parse number")
for i in 0..3
);
是否可以以扩展向量的方式声明元组?
答案 0 :(得分:7)
你不能使用类似Python的列表理解,因为Rust没有它。最接近的是通过另一个迭代器显式地完成它。你不能直接收集到一个元组,所以你需要另一个明确的步骤来转换矢量:
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);
}
}
如果您想避开中间向量,可以执行以下操作:
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);
}
}
答案 1 :(得分:2)
您可以使用类似于Iterator::collect
的方法声明特征并实现它以收集到各种元组大小:
awk '{if ( != "#include \"foobar.h\"") {print }}' ../foo/foo.h >> bar.c
awk: {if ( != "#include \"foobar.h\"") {print }}
awk: ^ syntax error
其他例子:
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);
答案 2 :(得分:0)
如果您想要更好的 IDE 类型提示,宏可能不是一个完美的解决方案。这是我的尝试:
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]) }