Comments 40
Так вот, если вы не против, я бы посоветовал свой вариант для примера с функциями высшего порядка:
use std::iter::FromIterator;
fn map_each(list: &[String], fun: fn(&String) -> usize) -> Vec<usize> {
Vec::from_iter(list.iter()
.map(fun))
}
fn main() {
let list = vec![
String::from("Python"),
String::from("Rust"),
String::from("Go"),
String::from("Haskell"),
];
let out = map_each(&list, String::len);
println!("{:?}", out); // [6, 4, 2, 7]
}
1. вектор можно создавать из итератора;
2. можно использовать вот такой подход.
А если вы не против, то ещё один комментарий по поводу следующего примера (не знаю, насколько это сильно отличается от вашей идеи), но я могу предложить такой вот вариант:
fn main() {
let output = ["42", "43", "sorokchetire"]
.iter()
.map(ToOwned::to_owned)
.map(&str::parse::<i32>)
.filter_map(Result::ok)
.map(|integer| integer * 2)
.fold(0, |base, element| base + element);
println!("{:?}", output);
}
Спасибо большое за комментарий! Ваши примеры выглядят более "rust"-way, если можно так сказать, и, безусловно, имеют место быть.
В самой статье, примеры на rust иногда, в некоторых местах, сознательно старались приблизить к python версии, чтоб сконцентрировать внимание на определённых деталях и упростить понимание того, что происходит в коде для тех кто с rust не знаком.
Ссылка на parse
во втором map
не нужна. Ну и первый map
делает ненужную аллокацию:
let output: i32 = ["42", "43", "sorokchetire"]
.iter()
.map(|value| value.parse::<i32>())
.filter_map(Result::ok)
.map(|integer| integer * 2)
.sum();
Спасибо. Я пробовал как-нибудь избежать использования ToOwned, но не смог подобрать нужное описание функции (я хотел не использовать замыкание в этом случае), но не смог избежать &&str, когда мне нужен был &str.
А по поводу sum, я смею предположить, что вы используете itertools крейт.
"std::iter::Sum — Rust" https://doc.rust-lang.org/std/iter/trait.Sum.html#tymethod.sum
Он вполне себе в стд либе
Проблему с двойной ссылкой нельзя обойти из-за того, что массивы в Rust пока нельзя преобразовать в итератор по-значению, а не по-ссылке. Но вскоре это будет исправлено. Тогда можно будет писать так:
let output: i32 = ["42", "43", "sorokchetire"]
.into_iter()
.map(str::parse::<i32>)
.filter_map(Result::ok)
.map(|integer| integer * 2)
.sum();
Бессмысленно превозносить компилируемые языки за то, что они выполняют проверку всего кода программы в процессе сборки. У скриптовых языков этот момент просто отсутствует.
Бессмысленно превозносить поддержку многопоточности в раст, она конечно круче питонячей, потому что питон изначально не создавался для потоков. Пока vm питона не научат атомарно исполнять его байткод и нормально масштабироваться по ядрам процессора его потоки так и останутся приделанным сбоку.
На счет функциональщины и замыканий — не убедили. Писать в функциональной манере можно, коли пришла такая охота, и кому это интересно, те знают про functools. Другое дело — это вопрос целесообразности. Питон, все таки ОО язык, и профит от чуждой парадигмы, лично для меня, не очевиден.
Финальная ремарка вообще убила: «Зачем-же питонисту Rust». Затем, зачем и все другие компилируемые языки, реализовать то, что сам питон делает плохо, например, распараллелить и/или ускорить какую нибудь задачу.
Дело вовсе не в производительности готовых программ, дело в производительности разработки. Вы не уловили главный вывод этого доклада: на Python получается быстрее разрабатывать с нуля, но дорабатывать и поддерживать систему, тем более крупную, быстрее и легче на Rust, так как он кучу важных проверок выносит на этап компиляции. В этой плоскости языки можно и нужно сравнивать, чтобы стало понятно, что лучше взять для быстрой разработки прототипа, который собрал и выкинул, а что лучше взять для разработка MVP, который предполагается дальше развивать продолжительное время.
на Python получается быстрее разрабатывать с нуля, но дорабатывать и поддерживать систему, тем более крупную, быстрее и легче на Rust
Это справедливо вообще для любой пары из скриптового и компилируемого языка
Как вы думаете, какую систему будет проще дорабатывать и поддерживать, написанную на Python или на C?
И в чем же преимущество возраста С?
Понятия не имею, вы откуда-то взяли возраст — вы и отвечайте.
UPD:
Это же не вино или коньяк
Знаете, COBOL тоже не алкогольный напиток, но от него избавляться не хотят / не могут, в частности из-за того, что программы многолетней «выдержки» очень уж хорошо отлажены, а заново написанные — неизвестно.
Я в продакшене (в самом широком смысле) с Python-скриптами (в любом виде) сталкиваюсь прилично реже, чем с C-кодом. Беру телефон в руки — там Python'ом вообще не пахнет (правда и C не так много, но хотя бы в самой ОС имеется), смотрю видео или слушаю музыку в браузере не на Python, а на C (а ещё кодеки, кодеки уж точно на C или вовсе ассемблерные!), как редактор какой запустить — там и LibreOffice, и Notepad++, и VS Code, и тем более Qt Creator в основном на плюсах… На работе Python видел только в форме небольших утилитарных скриптов (по уровню функционала — как раз прототипы), всё остальное — C. Хотя вру — изредка приходится обучать нейронку с помощью TensorFlow — но потом всё равно веса экспортируем в C-хедер, потому что бекенд-то Сишный
Тем не менее, большая часть сайтов в Интернете написана на PHP. А в браузере у вас выполняется в основном JavaScript. А вот на чем написан типичный браузер: https://4e6.github.io/firefox-lang-stats/ Доля именно C там не подавляющая. Мобильные приложения — это Java и Kotlin (или Swift).
А ещё по вашей ссылке выходит, что в Firefox больше используется HTML, чем C — вы тоже скажете, что он «выполняется»?
Вы с темы не съезжайте. Речь шла именно про язык С. Если вам нужно написать приложение для браузера, вы все еще возьмете JavaScript (ну или в недалеком будущем Rust, но сейчас не об этом) и вам все равно, на каком языке написан его интерпретатор. Я не умоляю значения языка С, но я сильно сомневаюсь в вашем утверждении, что любой компилируемый язык (для примера С) подходит лучше для разработки сложных систем любого другого интерпретируемого языка (Python, PHP, JavaScript).
Окей, расшифрую. Внезапно, WebAssembly позволяет писать фронтенд на C.
А ещё, браузерный фронтенд — это не весь-весь-весь продакшен-код, есть и бекенд, и всё, что вообще не связано с браузерами — и там JS не очень любят (ну, есть, конечно, NodeJS, но её используют в основном фронтендеры для сборки своего проекта, или кто «АААА, бекенд надо, а я кроме JS не знаю ничего»).
К счастью, подавляющее большинство софта всё ещё написано на компилиуемых языках — на своём домашнем компьютере я явно ни одно приложение на скриптовых языках не запускаю. А вот C/C++/.Net/Java приложения — запускаю, по многу раз каждый день. Вы опять скажете про браузеры — ну что поделать, если W3C не добавляет поддержку компилируемых модулей (кроме того же WebAssembly).
Но чем тут хорош именно сам COBOL — непонятно
Оглядываясь на обе статьи вместе, у меня сложилось впечатление, что автор просто неправильно выбрал инструмент, и теперь очень расстроен, что он оказался не достаточно, для него, универсален.
PS Всех с наступающим новым годом.
Быстрее разрабатывать именно крупные системы, заметьте. Делать a + b
вообще говоря все равно, на каком языке. А вот когда вы можете на высоком уровне оперировать множеством компонентов и легко связывать их в нечто более крупное… Но потом это крупное нужно поддерживать. Но потом это крупное требует особого тюнинга и нужно спускаться на уровень ниже. И та легкость и незамутненность типами, которая помогала на первом этапе, вдруг становится серьезным тормозом дальнейшего развития системы.
Вообще, JS — это не язык для надёжного программирования и серьёзных проектов. Это вспомогательный язык-скрипт. И очень плохо, что его пытаются переделать в Java вместо того, чтобы создать с нуля для своих целей другой язык, например на основе чего-то типа WebAssebmler — тот же TypeScript или Java-поверх-WebAsm, а не ограничение и уродование изумительного скриптового языка на основе прототипов, которым является (являлся?) JavaScript. Вместо создания нужных языков с нуля, их пытаются сделать поверх JavaScript, для чего сам JavaScript неудачно допиливают напильниками и ограничивают, чтобы не дай бог чего не вышло. Вот toSource(), например, зачем убрали? Удобная штука, и для совместимости со старым кодом нужная. Ломать — не строить…
Как мы уже говорили, питонисту очень многое приходится делать самому — проверять типы, держать в голове, где будет None, а где число, искать в документации, какие исключения может выбросить функция.
Задам этот вопрос ещё раз — а вы точно python разработчик? Дело в том что разработчики на ДТ языках не думают так как вы описали, такие проблемы просто не встают.
Больше похоже как будто вы после Java/C#/C++ решили поработать с Python и перенесли практики в него которые естественно не заработали.
Дело в том что разработчики на ДТ языках не думают так как вы описали
А как именно они думают? Или они не думают, а тупо исправляют баги, когда те проявят себя?
Rust глазами Python-разработчика #2