Изучение концепций программирования, погружаясь в глубину
Перевод | Автор оригинала: Pascal Hertleif
Есть много разных способов чему-то научиться; время от времени мне нравится то, что я бы назвал «прыжком в самый конец»: посмотрите на решение проблемы и изучите каждую из его деталей, пока не поймете все концепции.
Это контрастирует с обучением в стиле учебника, когда вы изучаете одно за другим и постепенно создаете более сложные вещи. Мне нравится подход «глубокого конца», потому что это очень личный стиль обучения. Это часто дает мне возможность самому открывать для себя интересные аспекты вещей, пытаться выяснить, как части работают вместе, и экспериментировать с материалом, пока я не пойму, как это работает. И хотя путь к пониманию может быть полон небольших разочарований и упущенных знаний, я считаю его очень полезным упражнением. (Или, может быть, я просто один из тех, кто любит разбираться в аккуратных концепциях.)
Недавно я столкнулся с такой задачей: подсчитать отдельные слова в заданном тексте. Решение, которое я нашел, показалось мне хорошей «глубокой проблемой». Он короткий, но в то же время полон разных концепций.
Вот что я бы написал (на Rust):
use std::collections::HashMap;
fn count_words(text: &str) -> HashMap<&str, usize> {
text.split(' ').fold(
HashMap::new(),
|mut map, word| { *map.entry(word).or_insert(0) += 1; map }
)
}
Всего 8 строк! (Вы можете поиграть с кодом здесь.)
И вот концепции, которые вам следует изучить, чтобы полностью понять, что происходит (в произвольном порядке; я попытался добавить много ссылок):
- Функции: fn count_words
- Модули и импорт: используйте std ::…
- Строки и символы: &str и '' гарантированно соответствуют UTF-8.
- Срезы: просмотры / ссылки на память и, в Rust, их время жизни: &strs в хеш-карте - это срезы входного текста.
- Итераторы: split возвращает тип, реализующий итератор.
- fold (a.k.a. reduce): основная часть функционального программирования (подробнее)
- Итератор: трэйта
- Тип данных карты: HashMap
- Хеширование
- Общие типы данных: Split <'a, P>, HashMap <K, V>
- API входа в Rust: просмотр карты с возможностью преобразования / добавления элементов.
- Где определяется входной API? RFC 216, RFC 509, RFC 921
- Перечисления: enum Entry {Занято (…), Вакантно (…)}
- замыкания: | x, y | {…}
- Неявный возврат, возвращается последнее выражение в блоке: {…; map} возвращает карту
- утверждения и выражения
- Изменяемые и неизменяемые привязки переменных: карта mut
- Ссылки, указатели, разыменование: *thingy and &thingy
- Целочисленные размеры: usize
- Встроенные операторы: + =
Обратите внимание, что большинство этих концепций не являются специальными для Rust. Я только что написал это на Rust, потому что это язык, который я использую чаще всего в свободное время, а также потому, что это язык, который открывает вам множество интересных концепций.
Для сравнения, вот то же самое в JavaScript (поиграйте с ним на JSBin):
function count_words(text) {
return text.split(' ')
.reduce((map, word) => {
map[word] = map[word] ? map[word] + 1 : 1;
return map;
}, {});
}
Спасибо за чтение.