Хочу ещё добавить, что разделение «массивов» на owned vectors, которые, собственно, являются владельцами куска памяти, и срезов, которые просто предоставляют окно в уже существующий кусок памяти (естественным образом вытекающее из концепций владения и заимствования), на мой взгляд, удобнее и понятнее в работе, чем модель, когда сами срезы владеют памятью, на которую указывают.
У нас с вами, видимо, разное понимание понятия «автоматически». Ещё раз:
для того, чтобы изменить версию гредла, которая будет использоваться при ./gradlew, нужно изменить версию в build.gradle и запустить ./gradlew wrapper
для того, чтобы изменить версию sbt, которая будет использоваться при ./sbt, нужно изменить версию в project/build.properties
Ключевой момент: в первом пункте нужно запустить команду для перегенерации враппера, во втором пункте делать ничего не нужно. Это именно то, что я подразумеваю под «автоматически».
Писать скрипт для системы, которая сама ничего не умеет, это что ли «автоматически» ??
Про что вы вообще говорите? Есть скрипт из официальной поставки sbt, который вы получите в /usr/local/bin или /usr/bin после brew install sbt/pacman -S sbt/прочее — он понимает build.properties. Есть скрипт из sbt-extras, который вы можете скачать из репозитория github.com/paulp/sbt-extras и поместить в корень проекта — он тоже понимает build.properties. Ткните, пожалуйста, пальцем, где здесь «сама ничего не умеет»? Если вам так не нравится слово «скрипт», то напомню, что и gradle, и gradlew — это тоже скрипты, которые вызывают соответствующие джарники. Разница с sbt исключительно в том, что гредл умеет генерировать враппер сам, а sbt — нет.
Как лихо вы выкинули встроенную функцию gradle, сделав какую-то фигю.
Я не понимаю, что вы имеете в виду. Я ничего никуда не выкидывал. Скажите, в чём конкретно я не прав в тех шагах, которые я привёл.
Это абсолютно корректно. Ибо враппер это встроенная функция гредла. Все что надо это изменить версию гредла в build.gradle.
Я не спорил, что генерация враппера — это встроенная функция. Я говорю про то, что для смены версии гредла недостаточно «изменить версию в build.gradle», дополнительно нужно ещё перегенерировать враппер заново. Здесь нет никакого «автоматически».
В sbt этоq возможноcnb в принципе, хоть с запуском таски хоть без. Только наколенными костылями.
Я не понимаю, почему стандартный скрипт из поставки sbt вы называете костылём. Это то же самое, что назвать команду gradle, которая устанавливается системным пакетным менеджером, костылём. Да, я не спорю, что в sbt нет официального аналога gradle wrapper; но это совершенно ортогональная к управлению версиями проблема. build.properties понимается как официальным скриптом, так и sbt-extras.
сделали вывод, что гредл фигня
Не понимаю, где вы это увидели. Наоборот, я сказал что гредл мне очень нравится.
Я знаю как работает гредл; я делал на нём несколько проектов и довольно подробно изучал его документацию, и я даже писал к нему плагины. И именно поэтому мне правда интересно, как именно эта ваша магия работает. У меня её вызвать не получилось.
1. Создаю пустой каталог, в котором лежит build.gradle следующего содержания:
2. Поскольку у меня в системе уже установлен гредл, а каталог свежесозданный, в котором ничего, кроме build.gradle, нет, создаю враппер вызовом системного гредла:
% gradle wrapper
и проверяю версию:
% ./gradlew --version
------------------------------------------------------------
Gradle 2.4
------------------------------------------------------------
Build time: 2015-05-05 08:09:24 UTC
Build number: none
Revision: 5c9c3bc20ca1c281ac7972643f1e2d190f2c943c
Groovy: 2.3.10
Ant: Apache Ant(TM) version 1.9.4 compiled on April 29 2014
JVM: 1.8.0_66 (Oracle Corporation 25.66-b17)
OS: Mac OS X 10.10.5 x86_64
% ./gradlew --version
------------------------------------------------------------
Gradle 2.4
------------------------------------------------------------
Build time: 2015-05-05 08:09:24 UTC
Build number: none
Revision: 5c9c3bc20ca1c281ac7972643f1e2d190f2c943c
Groovy: 2.3.10
Ant: Apache Ant(TM) version 1.9.4 compiled on April 29 2014
JVM: 1.8.0_66 (Oracle Corporation 25.66-b17)
OS: Mac OS X 10.10.5 x86_64
Как было 2.4, так и осталось.
5. А вот если я перезапущу таску на враппер:
% ./gradlew wrapper
То после этого версия будет новая, как и ожидалось:
% ./gradlew --version
------------------------------------------------------------
Gradle 2.7
------------------------------------------------------------
Build time: 2015-09-14 07:26:16 UTC
Build number: none
Revision: c41505168da69fb0650f4e31c9e01b50ffc97893
Groovy: 2.3.10
Ant: Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM: 1.8.0_66 (Oracle Corporation 25.66-b17)
OS: Mac OS X 10.10.5 x86_64
6. Кроме того, на системный гредл версия в build.gradle не влияет (что естественно, потому что это просто настройка таски для гредла):
% gradle --version
------------------------------------------------------------
Gradle 2.8
------------------------------------------------------------
Build time: 2015-10-20 03:46:36 UTC
Build number: none
Revision: b463d7980c40d44c4657dc80025275b84a29e31f
Groovy: 2.4.4
Ant: Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM: 1.8.0_66 (Oracle Corporation 25.66-b17)
OS: Mac OS X 10.10.5 x86_64
Сравним с тем скриптом для sbt, про который я писал выше.
1. Создаю новый каталог, в нём файл project/build.properties с версией:
sbt.version=0.13.5
2. Сохраняю скрипт в файл sbt, запускаю его:
% ./sbt -v
No extra sbt options have been defined
Detected sbt version 0.13.5
Starting sbt: invoke with -help for other options
Using default jvm options
Detected Java version: 1.8.0_66
3. Меняю версию в build.properties:
sbt.version=0.13.9
4. Проверяю версию:
./sbt -v
No extra sbt options have been defined
Detected sbt version 0.13.9
Starting sbt: invoke with -help for other options
Downloading sbt launcher for 0.13.9:
From http://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/sbt-launch/0.13.9/sbt-launch.jar
To /Users/netvl/.sbt/launchers/0.13.9/sbt-launch.jar
Using default jvm options
Detected Java version: 1.8.0_66
5. Системный скрипт, кстати, тоже осведомлён о версиях sbt и выберет именно ту, которая указана в build.properties. Вообще, строго говоря, в системе устанавливается только скрипт-лаунчер, а версия sbt зависит только от build.properties, и сам sbt выкачивается в пользовательский каталог.
Не поймите меня неправильно, мне очень нравится гредл, и для Java-приложений я использую именно его и советую всем вокруг тоже. И у sbt есть множество проблем, в том числе и в семантике — например, я до сих пор не очень понимаю, как именно работают «автоматические» плагины, а система scope axis, скажем так, далека от интуитивно понятной; система плагинов в гредле мне тоже нравится больше. Но я просто хотел сказать, что в данном конкретном случае утверждать, что версия гредла указывается в build.gradle, а всё остальное делается автоматически, не совсем корректно.
Версия в gradle-wrapper.properties это вообще не конфиг для указания версии гредла, это результат работы вышеуказанной таски в которой указана версия, в виде адреса для скачивания архива с гредлом.
Безусловно. Я имел в виду, что именно gradle-wrapper.properties определяет версию, которая будет использоваться gradlew, и чтобы её обновить правильно, gradlew нужно перегенерировать вручную.
Это указание версии для враппера для таски gradle wrapper, а сам враппер нужно сгенерировать, чтобы получить скрипт для гредла нужной версии. Наличие этого в билде не означает, что вызвав gradle или ./gradlew в каталоге проекта, вы тут же получите гредл нужной версии — для этого вам нужно перегенерировать враппер, что можно сделать, только уже имея на руках гредл. Поэтому это совершенно неравноценные вещи, по сравнению с build.properties: аналогом build.properties у гредла будет gradle/wrapper/gradle-wrapper.properties:
популярные Opensource проекты, которые билдятся sbt
Это следствие того, что популярные проекты достаточно долго развиваются, и переделывать билд без веских на то причин никто не станет. Новые проекты, я думаю, всё-таки стараются следовать современным best practices. Dependencies.scala смысл имеет, на мой взгляд, но это на вкус и цвет.
Плюс ко всему SBT на порядок медленнее даже визуально. Еще у IDEA с SBT все намного печальнее, чем с Gradle(мне лично не хватает комплишена версий либ).
target-подкаталоги — это результаты компиляции кода проекта. sbtшная сборка — это тоже scala-код, который нужно компилировать. Это неизбежно — groovy может запускаться под интерпретатором, а scala — нет. Собственно, поэтому этой требухи в гредле и нет.
Отдельная папочка для проекта сделана для унификации (сборка на sbt компилируется sbt) и для того, чтобы было куда положить скальные сборочные файлы. Не мусорить же ими в корне проекта? Почему не было разрешено положить Build.scala в корень проекта, я не знаю, но теперь это в любом случае неактуально — писать билды в scala-файлах уже нет необходимости.
Два формата описания сборки — это, к сожалению, пережиток прошлого. В скале, когда sbt создавался, не было макросов и прочих удобств, и сборочные скрипты на чистой скале выглядели страшно. Scala — не скриптовый и не интерпретируемый язык, и сделать синтаксис как в груви там не получится. Для этого сделали упрощённый формат в build.sbt, в котором можно по-быстрому задать основные настройки, а если нужно что-то более сложное, то необходимо юзать скалу напрямую. Однако сейчас формат sbt и скальных билдов становится всё более унифицированным, и сейчас по сути в sbt-файлах можно свободно писать практически любой скальный код. Описывать именно параметры сборки, т.е. зависимости, версию языка, опции компилятора и прочее, в скальном билде сейчас наоборот не рекомендуется, лучше использовать build.sbt. В project, как я уже писал, нужно хранить прочий код, вроде генерации тестов и схожего барахла, и здесь как раз хорошо, что есть отдельный каталог для этого.
Насчёт версии сборки — потому что для того, чтобы вообще прочитать и проанализировать файл сборки, нужно иметь в наличии sbt, а как вы узнаете тогда, какую версию sbt качать? Насколько я вижу, в гредле версия тоже не определяется в build.gradle, а зависит от того, что было указано при вызове таски wrapper, и она запрятана где-то внутри каталога wrapper.
Насчёт отсутствия враппера в официальной поставке — ничего не могу сказать. Лично я не испытываю от его отсутствия неудобств, установить дополнительный пакет пакетным менеджером в систему несложно.
Ну на самом деле sbt очень сильно проэволюционировал за последние несколько лет. Когда я его видел в версиях 0.11-0.12 и более ранних, у меня было совершенно такое же ощущение, что и у вас. Однако в версии 0.13, которая сейчас последняя, sbt стал весьма удобен. Для простых и средних проектов в sbt достаточно одного файла, build.sbt. Для сложных проектов с дополнительными настройками, кодо/тестогенерацией, публикацией артефактов и прочим в любом случае имеет смысл разделить один-единственный билдскрипт на несколько, каждый из которых отвечает за свою часть.
Соответственно, структура 99% проектов на sbt выглядит как файл build.sbt в корне и файл build.properties в каталоге project/, в котором указана версия sbt. Строго говоря, в gradle тоже два или более файлов: build.gradle и settings.gradle, в котором нужно указывать иерархию проектов, и у каждого проекта свой build.gradle. «Кучи» вложенных каталогов в sbt тоже нет — есть подкаталог project, в который кладутся scala-файлы и build.properties, но, как я уже сказал, в 99% случаев ничего, кроме build.properties там не будет, если вы сами не захотите. Также там в отдельном файле прописываются дополнительные плагины, если они вам нужны; да, в этом случае будет отдельный файл, когда в gradle плагины описываются в отдельной секции в основном скрипте, но лично на мой взгляд, это совершенно непринципиальная разница.
Вот, например, мой проект на sbt. Сборка состоит из нескольких проектов, причём все они определены в build.sbt. В project/ есть несколько файлов, это build.properties с версией, plugins.sbt с описанием плагинов, TestGeneration.scala с кодом, который генерирует тесты, и build.sbt, в котором указаны зависимости для TestGeneration (я, кстати, не знаю, можно ли так сделать в Gradle без отдельного плагина, хотя, наверное, можно). На мой взгляд, ничего особо сложного в структуре сборки там нет.
Замечание насчёт враппера справедливо наполовину: у sbt есть (неофициальный) скрипт, который работает точно так же, как и gradlew: если хотите, вы можете закоммитить его в свой проект и запускать sbt как ./sbt. Он выкачает нужную версию sbt автоматически. Этот же скрипт можно установить при желании и глобально. Но да, в стандартную поставку sbt возможность генерации враппера не входит, и я согласен, это было бы очень удобно.
А можно поинтересоваться, чем вам неудобен sbt? Например, лично на мой взгляд, он гораздо удобнее мавена и даже гредла.
И что там за проблема с компиляцией под разные версии Scala? Кажется, сейчас в sbt есть для этого все инструменты. Если правильно написать билдскрипт, что совсем не сложно, то для компиляции и деплоя артефактов для всех версий скалы можно написать просто +publish в консоли sbt. Да, к сожалению, есть проблемы с совместимостью, если вы используете компиляторозависимые вещи вроде макросов, и здесь приходится делать костыли, но, как мне кажется, проектов с такими особенностями совсем мало.
Размер артефактов — да, есть такая проблема. Поэтому, например, из основного дистрибутива скалы и начали вычищать лишнее, вроде XML.
Хочу отметить, что при создании SBT-проекта лучше не выбирать «Use auto import». Эта опция заставит среду перечитывать все проектные файлы практически на каждое изменение файла. Если в вашей сборке больше нескольких проектов, это будет делаться оооочень долго — например, в сборке на ~80 проектов обновление зависимостей делается около пяти минут. Лучше отключить эту опцию и запускать обновление вручную, через боковую панель. В конце концов, зависимости у проектов обычно обновляются не очень часто.
Большое спасибо за статью! Очень здорово, что по Rust они появляются и на русском.
Пара замечаний. Во-первых, идиоматично переиспользовать имена переменных в паттернах наподобие того, что демонстрирует ваш код:
let sdb = Arc::new(Mutex::new(db));
{
let sdb = sdb.clone();
thread::spawn(move || do_something(sdb));
}
Т.е. не нужно добавлять суффиксов-префиксов, можно просто переопределить (в смысле rebind, а не reassign) существующую переменную.
Во-вторых, where — это не «задание краткого имени для длинного типа», это определение ограничений на дженериковую ти́повую переменную:
fn do_something<T: 'a + Trait1 + Trait2 + Trait3>() { ... }
// equivalent to
fn do_something<T>() where T: 'a + Trait1 + Trait2 + Trait3 { ... }
Обычно where используется, если ограничений много или если они большие (например, большая сигнатура замыкания), потому что в таком случае их проще будет распределить по нескольким строчкам. Если ограничения простые (один-два коротких трейта), то чаще используется синтаксис с ограничениями в списке параметров.
Да, но в подавляющем большинстве случаев если вы используете только &str, то разрешать передавать String нет никакого смысла — в этом случае произойдёт передача права владения, которая совершенно бессмысленна, если используется только &str. Поэтому я и говорю, что я не вижу смысла в AsRef.
Спасибо за статью! mio выглядит довольно интересно. С ней, кстати, работают такие библиотеки как mioco и coio-rs, которые дают чуть более высокоуровневый интерфейс. Может быть, их тоже возможно как-то применить в вашем случае?
Пара небольших замечаний: в функцию gen_key лучше передавать &str, а не &String — &String вообще никогда не имеет смысла использовать, а конструкцию типа "abcde".as_bytes() можно заменить на b"abcde".
Дебаг лямбда-выражений по отдельности — это очень круто, но очень хотелось бы такое получить в Scala-плагине для анонимных функций. Это одна из немногих вещей, отсутствие которой делает дебаг сложных выражений со многими функциями высшего порядка очень неудобным. Планируется ли что-то такое?
docopt не стал пользоваться потому что показалось, что это достаточно просто сделать самому (в отличие от разбора INI). Заодно показал, как пользоваться match.
Ну если для обучения, то смысл это имеет, хотя показать различные библиотеки и посоветовать не переизобретать велосипеды тоже хорошо :)
reversed(items)
возвращает итератор:который, судя по названию, делает то же самое, что цикл с убывающим индексом, только удобнее. Поэтому в алгоритмической сложности разницы нет вообще.
Ключевой момент: в первом пункте нужно запустить команду для перегенерации враппера, во втором пункте делать ничего не нужно. Это именно то, что я подразумеваю под «автоматически».
Про что вы вообще говорите? Есть скрипт из официальной поставки sbt, который вы получите в
/usr/local/bin
или/usr/bin
послеbrew install sbt
/pacman -S sbt
/прочее — он понимает build.properties. Есть скрипт из sbt-extras, который вы можете скачать из репозитория github.com/paulp/sbt-extras и поместить в корень проекта — он тоже понимает build.properties. Ткните, пожалуйста, пальцем, где здесь «сама ничего не умеет»? Если вам так не нравится слово «скрипт», то напомню, что и gradle, и gradlew — это тоже скрипты, которые вызывают соответствующие джарники. Разница с sbt исключительно в том, что гредл умеет генерировать враппер сам, а sbt — нет.Я не понимаю, что вы имеете в виду. Я ничего никуда не выкидывал. Скажите, в чём конкретно я не прав в тех шагах, которые я привёл.
Я не спорил, что генерация враппера — это встроенная функция. Я говорю про то, что для смены версии гредла недостаточно «изменить версию в build.gradle», дополнительно нужно ещё перегенерировать враппер заново. Здесь нет никакого «автоматически».
Я не понимаю, почему стандартный скрипт из поставки sbt вы называете костылём. Это то же самое, что назвать команду gradle, которая устанавливается системным пакетным менеджером, костылём. Да, я не спорю, что в sbt нет официального аналога gradle wrapper; но это совершенно ортогональная к управлению версиями проблема. build.properties понимается как официальным скриптом, так и sbt-extras.
Не понимаю, где вы это увидели. Наоборот, я сказал что гредл мне очень нравится.
1. Создаю пустой каталог, в котором лежит build.gradle следующего содержания:
2. Поскольку у меня в системе уже установлен гредл, а каталог свежесозданный, в котором ничего, кроме build.gradle, нет, создаю враппер вызовом системного гредла:
и проверяю версию:
3. Изменяю версию в таске:
4. Проверяю версию:
Как было 2.4, так и осталось.
5. А вот если я перезапущу таску на враппер:
То после этого версия будет новая, как и ожидалось:
6. Кроме того, на системный гредл версия в build.gradle не влияет (что естественно, потому что это просто настройка таски для гредла):
Сравним с тем скриптом для sbt, про который я писал выше.
1. Создаю новый каталог, в нём файл project/build.properties с версией:
2. Сохраняю скрипт в файл sbt, запускаю его:
3. Меняю версию в build.properties:
4. Проверяю версию:
5. Системный скрипт, кстати, тоже осведомлён о версиях sbt и выберет именно ту, которая указана в build.properties. Вообще, строго говоря, в системе устанавливается только скрипт-лаунчер, а версия sbt зависит только от build.properties, и сам sbt выкачивается в пользовательский каталог.
Не поймите меня неправильно, мне очень нравится гредл, и для Java-приложений я использую именно его и советую всем вокруг тоже. И у sbt есть множество проблем, в том числе и в семантике — например, я до сих пор не очень понимаю, как именно работают «автоматические» плагины, а система scope axis, скажем так, далека от интуитивно понятной; система плагинов в гредле мне тоже нравится больше. Но я просто хотел сказать, что в данном конкретном случае утверждать, что версия гредла указывается в build.gradle, а всё остальное делается автоматически, не совсем корректно.
Безусловно. Я имел в виду, что именно gradle-wrapper.properties определяет версию, которая будет использоваться gradlew, и чтобы её обновить правильно, gradlew нужно перегенерировать вручную.
где, собственно, и можно наблюдать конкретную версию гредла.
Выше вы писали, что не в курсе:
Собственно, на это я и отвечал. Какая, по-вашему, была бы не корявая реализация, с учётом того, что Scala нельзя интерпретировать так же, как груви?
Это следствие того, что популярные проекты достаточно долго развиваются, и переделывать билд без веских на то причин никто не станет. Новые проекты, я думаю, всё-таки стараются следовать современным best practices. Dependencies.scala смысл имеет, на мой взгляд, но это на вкус и цвет.
Здесь, к сожалению, не могу не согласиться :(
Отдельная папочка для проекта сделана для унификации (сборка на sbt компилируется sbt) и для того, чтобы было куда положить скальные сборочные файлы. Не мусорить же ими в корне проекта? Почему не было разрешено положить Build.scala в корень проекта, я не знаю, но теперь это в любом случае неактуально — писать билды в scala-файлах уже нет необходимости.
Два формата описания сборки — это, к сожалению, пережиток прошлого. В скале, когда sbt создавался, не было макросов и прочих удобств, и сборочные скрипты на чистой скале выглядели страшно. Scala — не скриптовый и не интерпретируемый язык, и сделать синтаксис как в груви там не получится. Для этого сделали упрощённый формат в build.sbt, в котором можно по-быстрому задать основные настройки, а если нужно что-то более сложное, то необходимо юзать скалу напрямую. Однако сейчас формат sbt и скальных билдов становится всё более унифицированным, и сейчас по сути в sbt-файлах можно свободно писать практически любой скальный код. Описывать именно параметры сборки, т.е. зависимости, версию языка, опции компилятора и прочее, в скальном билде сейчас наоборот не рекомендуется, лучше использовать build.sbt. В project, как я уже писал, нужно хранить прочий код, вроде генерации тестов и схожего барахла, и здесь как раз хорошо, что есть отдельный каталог для этого.
Насчёт версии сборки — потому что для того, чтобы вообще прочитать и проанализировать файл сборки, нужно иметь в наличии sbt, а как вы узнаете тогда, какую версию sbt качать? Насколько я вижу, в гредле версия тоже не определяется в build.gradle, а зависит от того, что было указано при вызове таски wrapper, и она запрятана где-то внутри каталога wrapper.
Насчёт отсутствия враппера в официальной поставке — ничего не могу сказать. Лично я не испытываю от его отсутствия неудобств, установить дополнительный пакет пакетным менеджером в систему несложно.
Соответственно, структура 99% проектов на sbt выглядит как файл build.sbt в корне и файл build.properties в каталоге project/, в котором указана версия sbt. Строго говоря, в gradle тоже два или более файлов: build.gradle и settings.gradle, в котором нужно указывать иерархию проектов, и у каждого проекта свой build.gradle. «Кучи» вложенных каталогов в sbt тоже нет — есть подкаталог project, в который кладутся scala-файлы и build.properties, но, как я уже сказал, в 99% случаев ничего, кроме build.properties там не будет, если вы сами не захотите. Также там в отдельном файле прописываются дополнительные плагины, если они вам нужны; да, в этом случае будет отдельный файл, когда в gradle плагины описываются в отдельной секции в основном скрипте, но лично на мой взгляд, это совершенно непринципиальная разница.
Вот, например, мой проект на sbt. Сборка состоит из нескольких проектов, причём все они определены в build.sbt. В project/ есть несколько файлов, это build.properties с версией, plugins.sbt с описанием плагинов, TestGeneration.scala с кодом, который генерирует тесты, и build.sbt, в котором указаны зависимости для TestGeneration (я, кстати, не знаю, можно ли так сделать в Gradle без отдельного плагина, хотя, наверное, можно). На мой взгляд, ничего особо сложного в структуре сборки там нет.
Замечание насчёт враппера справедливо наполовину: у sbt есть (неофициальный) скрипт, который работает точно так же, как и gradlew: если хотите, вы можете закоммитить его в свой проект и запускать sbt как ./sbt. Он выкачает нужную версию sbt автоматически. Этот же скрипт можно установить при желании и глобально. Но да, в стандартную поставку sbt возможность генерации враппера не входит, и я согласен, это было бы очень удобно.
И что там за проблема с компиляцией под разные версии Scala? Кажется, сейчас в sbt есть для этого все инструменты. Если правильно написать билдскрипт, что совсем не сложно, то для компиляции и деплоя артефактов для всех версий скалы можно написать просто
+publish
в консоли sbt. Да, к сожалению, есть проблемы с совместимостью, если вы используете компиляторозависимые вещи вроде макросов, и здесь приходится делать костыли, но, как мне кажется, проектов с такими особенностями совсем мало.Размер артефактов — да, есть такая проблема. Поэтому, например, из основного дистрибутива скалы и начали вычищать лишнее, вроде XML.
Пара замечаний. Во-первых, идиоматично переиспользовать имена переменных в паттернах наподобие того, что демонстрирует ваш код:
Т.е. не нужно добавлять суффиксов-префиксов, можно просто переопределить (в смысле rebind, а не reassign) существующую переменную.
Во-вторых,
where
— это не «задание краткого имени для длинного типа», это определение ограничений на дженериковую ти́повую переменную:Обычно
where
используется, если ограничений много или если они большие (например, большая сигнатура замыкания), потому что в таком случае их проще будет распределить по нескольким строчкам. Если ограничения простые (один-два коротких трейта), то чаще используется синтаксис с ограничениями в списке параметров.Пара небольших замечаний: в функцию gen_key лучше передавать &str, а не &String — &String вообще никогда не имеет смысла использовать, а конструкцию типа
"abcde".as_bytes()
можно заменить наb"abcde"
.Ну если для обучения, то смысл это имеет, хотя показать различные библиотеки и посоветовать не переизобретать велосипеды тоже хорошо :)