Rust 是否与 Python 的字典理解语法等效?

Sea*_*nka 9 list-comprehension rust

如何将以下 Python(其中读取多个文件并将它们的内容用作字典(以文件名作为键)的值)转换为 Rust?

countries = {region: open("{}.txt".format(region)).read() for region in ["canada", "usa", "mexico"]}
Run Code Online (Sandbox Code Playgroud)

我的尝试如下所示,但我想知道是否可以使用单行惯用的解决方案。

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") };
}
Run Code Online (Sandbox Code Playgroud)

gil*_*lch 17

锈病的迭代器有map/ filter/collect方法,它们是够做任何事Python的内涵可以。您可以在成对的迭代器上创建HashMapwith collect,但collect可以返回各种类型的集合,因此您可能必须指定所需的类型。

例如,

use std::collections::HashMap;

fn main() {
    println!(
        "{:?}",
        (1..5).map(|i| (i + i, i * i)).collect::<HashMap<_, _>>()
    );
}
Run Code Online (Sandbox Code Playgroud)

大致相当于Python

use std::collections::HashMap;

fn main() {
    println!(
        "{:?}",
        (1..5).map(|i| (i + i, i * i)).collect::<HashMap<_, _>>()
    );
}
Run Code Online (Sandbox Code Playgroud)

但从字面上翻译,它实际上更接近于

print({i+i: i*i for i in range(1, 5)})
Run Code Online (Sandbox Code Playgroud)

并不是说你会在 Python 中这样说。


gil*_*lch 10

Python 的理解只是 for 循环和累加器的糖。Rust 有宏——你可以制作任何你想要的糖。

以这个简单的 Python 示例为例,

print({i+i: i*i for i in range(1, 5)})
Run Code Online (Sandbox Code Playgroud)

您可以轻松地将其重写为循环和累加器:

map = {}
for i in range(1, 5):
    map[i+i] = i*i
print(map)
Run Code Online (Sandbox Code Playgroud)

你可以在 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);
}
Run Code Online (Sandbox Code Playgroud)

您可以使用宏为您重写此表单。

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);
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

当您使用它时,生成的代码要紧凑得多。并且这种分隔符标记的选择使其类似于 Python。

fn main() {
    hashcomp!(hm = i+i => i*i; for i in 1..5);
    println!("{:?}", hm);
}
Run Code Online (Sandbox Code Playgroud)

这只是一个可以处理单个循环的基本示例。Python 的推导式也可以有过滤器和额外的循环,但更高级的宏可能也可以做到这一点。