Имеет ли Rust эквивалент синтаксиса понимания словаря Python? - PullRequest
0 голосов
/ 09 декабря 2018

Как можно перевести следующий Python, в котором несколько файлов читаются и их содержимое используется в качестве значений в словарь (с именем файла в качестве ключа), в Rust?

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 голосов
/ 09 декабря 2018

Итераторы 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)))))
0 голосов
/ 09 декабря 2018

Понимание Python - просто сахар для цикла for и аккумулятора.Rust имеет макросов - вы можете сделать любой сахар, какой захотите.

Возьмите этот простой пример 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 также могут иметь фильтры и дополнительные циклы, но более продвинутый макрос, вероятно, тоже может это сделать.

...