Rust是否具有与Python的字典理解语法等效的功能?

时间:2018-12-09 00:00:34

标签: rust list-comprehension

一个人如何将下面的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") };
}

2 个答案:

答案 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的理解能力还可以包含过滤器和其他循环,但是更高级的宏也可以做到这一点。