一个人如何将下面的Python转换为Rust,该Python中读取了多个文件并将它们的内容用作字典(以文件名作为键)的值。
countries = {region: open("{}.txt".format(region)).read() for region in ["canada", "usa", "mexico"]}
下面显示了我的尝试,但我想知道一种单行惯用的解决方案是否可能。
use std::{
fs::File,
io::{prelude::*, BufReader},
path::Path,
collections::HashMap,
};
macro_rules! map(
{ $($key:expr => $value:expr),+ } => {
{
let mut m = HashMap::new();
$(
m.insert($key, $value);
)+
m
}
};
);
fn lines_from_file<P>(filename: P) -> Vec<String>
where
P: AsRef<Path>,
{
let file = File::open(filename).expect("no such file");
let buf = BufReader::new(file);
buf.lines()
.map(|l| l.expect("Could not parse line"))
.collect()
}
fn main() {
let _countries = map!{ "canada" => lines_from_file("canada.txt"),
"usa" => lines_from_file("usa.txt"),
"mexico" => lines_from_file("mexico.txt") };
}
答案 0 :(得分:4)
Rust的迭代器具有map
/ filter
/ collect
方法,这些方法足以完成Python的所有理解。您可以在成对的迭代器上用HashMap
创建一个collect
,但是collect
可以返回各种类型的集合,因此您可能必须指定所需的类型。
例如,
use std::collections::HashMap;
fn main() {
println!(
"{:?}",
(1..5).map(|i| (i + i, i * i)).collect::<HashMap<_, _>>()
);
}
大致等同于Python
print({i+i: i*i for i in range(1, 5)})
尽管从概念上讲,它实际上更接近
print("{!r}".format(dict(map(lambda i: (i+i, i*i), range(1, 5)))))
答案 1 :(得分:2)
Python的理解只是for循环和累加器的糖。锈(Rust)有macros-您可以制作任何想要的糖。
以这个简单的Python示例为例,
print({i+i: i*i for i in range(1, 5)})
您可以轻松地将其重新编写为循环和累加器:
map = {}
for i in range(1, 5):
map[i+i] = i*i
print(map)
您可以在Rust中以基本相同的方式进行操作。
use std::collections::HashMap;
fn main() {
let mut hm = HashMap::new();
for i in 1..5 {
hm.insert(i + i, i * i);
}
println!("{:?}", hm);
}
您可以使用宏为您重写此表单。
use std::collections::HashMap;
macro_rules! hashcomp {
($name:ident = $k:expr => $v:expr; for $i:ident in $itr:expr) => {
let mut $name = HashMap::new();
for $i in $itr {
$name.insert($k, $v);
}
};
}
使用它时,生成的代码更加紧凑。这种分隔符的选择使其类似于Python。
fn main() {
hashcomp!(hm = i+i => i*i; for i in 1..5);
println!("{:?}", hm);
}
这只是一个可以处理单个循环的基本示例。 Python的理解能力还可以包含过滤器和其他循环,但是更高级的宏也可以做到这一点。