我正在编写一个宏来逐行解析一些结构化文本到元组中。大多数部分现在都可以工作,但是我坚持通过从向量中提取/转换字符串来形成元组。
// Reading Tuple from a line
// Example : read_tuple( "1 ab 3".lines()
// ,(i32, String, i32))
// Expected : (1, "ab", 3)
// Note:: you can note use str
macro_rules! read_tuple {
(
$lines :ident , ( $( $t :ty ),* )
)
=> {{
let l = ($lines).next().unwrap();
let ws = l.trim().split(" ").collect::<Vec<_>>();
let s : ( $($t),* ) = (
// for w in ws {
// let p = w.parse().unwrap();
// ( p) ,
// }
ws[0].parse().unwrap(),
ws[1].parse().unwrap(),
//...
ws[2].parse().unwrap(),
// Or any way to automatically generate these statments?
);
s
}}
}
fn main() {
let mut _x = "1 ab 3".lines();
let a = read_tuple!( _x, (i32, String, i32));
print!("{:?}",a);
}
如何遍历ws
并返回此宏中的元组?
你可以try here
答案 0 :(得分:3)
元组是异构集合;每个元素可以是不同的类型。在您的示例中,它们是的不同类型,因此每个parse
方法都需要生成不同的类型。因此,纯粹的运行时迭代是正确的;你确实需要扩展所有ws[N].parse().unwrap()
个语句。
遗憾的是,目前还没有任何方法可以写出$(…)*
的当前迭代(尽管可以使用编译器插件进行模拟)。但是,有一种方法可以解决这个问题:混合运行和编译时迭代。我们使用迭代器来提取字符串,并使用宏迭代扩展(确保在$t
中提到$(…)
,以便它知道要重复的内容)来生成相同行的正确数量。这也意味着我们可以避免使用中间向量,因为我们直接使用迭代器,所以我们全面赢了。
macro_rules! read_tuple {
(
$lines:ident, ($($t:ty),*)
) => {{
let l = $lines.next().unwrap();
let mut ws = l.trim().split(" ");
(
$(ws.next().unwrap().parse::<$t>().unwrap(),)*
)
}}
}
需要注意的一件小事是我如何将),*
更改为,)*
;这意味着您将获得()
,(1,)
,(1, 2,)
,(1, 2, 3,)
和&amp; c。代替()
,(1)
,(1, 2)
,(1, 2, 3)
- 关键区别在于单元素元组将起作用(尽管你仍然遗憾地写{{1} }})。