Структурата на един проект (3): функцията, която никой не можеше да тества
От Dorian Chávez · основател и главен изпълнителен директор на Hábil ·
Цялата ти логика е в main.rs и тестовете в tests/ не могат да я импортират, дори с pub. Какво отива в lib.rs, какво остава частно, и шаблон, който го проверява.
Структурата на един проект · част 3 от 7 · Rust
Сценарий: героите и историята са измислени. Техническите данни и цитатите са с източник в края.
За 1 минута
- В Rust тест в
tests/е друг crate. Той може да ползва само това, което една библиотека обявява заpub. Ако проектът ти има самоmain.rs, няма какво да се импортира [1]. - Изходът е програмата да се раздели: логиката в
src/lib.rsи тънъкmain.rs, който само я извиква [2][3]. - В Rust всичко е частно, докато не кажеш
pub[3][5]. Това не е досада: това е граница, която компилаторът пази, и тя ти позволява да променяш вътрешното, без да чупиш никого. - Взимаш шаблон, който се клонира и тръгва от първия път, със скрипт, който доказва тази граница, като става червен, когато трябва.
- За понеделник: потърси в проекта си кои функции от
main.rsзаслужават тест. Те отиват в библиотеката.
В тази статия
- Какво се случи във вторник в 19:20?
- Какво иска Rust Book?
- Кои са пет чести грешки?
- Упражнение: можеш ли да преминеш границата?
- Ключови изводи
- Какво следва?
- Шаблонът и курсът
- Какво прави Hábil?
- Източници
Какво се случи във вторник в 19:20?
Иван искаше да тества функция отвън, а компилаторът му отговори, че няма какво да се импортира.
Вторник, 19:20. Трети етаж.
Трета задача, първата на Rust. Пак проверителят — този от Go и от Python, който запитва услуги по HTTP. Поръчката: «Отчетът да не показва токените в URL адресите».
Програмата я беше писал някой, който вече го нямаше. Всичко живееше в един-единствен файл:
src/main.rs 900 líneas
Cargo.toml
Cargo.lockИван намери функцията, която сглобяваше URL адреса на отчета, около ред 600, и я поправи. Искаше тест, който да казва «токенът не излиза» — от тези, които живеят в tests/. Създаде tests/reporte.rs и написа, както в книгата:
use revisor::url_publica;cargo test. Отговорът (съкратен):
error[E0432]: unresolved import `revisor`
= help: if you wanted to use a crate named `revisor`, use `cargo add revisor` to add it to your `Cargo.toml`Crate на име revisor? Така се казваше проектът му. Сложи pub на функцията и пусна отново. Същата грешка, дума по дума. А подсказката сочеше към външен пакет; той искаше своя.
В 19:41 писа на Лусия, техническата ръководителка.
— Сложих pub и пак не я намира.
— Къде ти е библиотеката? — отговори тя.
— Нямам. Това е програма.
— Ето го проблема. Програмата не експортира нищо. Тестовете ти в tests/ са друг crate, а друг crate може да ползва само библиотека. Утре разделяме този main.rs на две.
Иван погледна 900-те реда. Компилаторът не му казваше, че кодът му е грешен. Казваше му, че няма врата.
Какво иска Rust Book?
Логиката да живее в библиотека, а main.rs само да я извиква, защото само библиотека може да се импортира отвън.
Главата за тестове в Rust Book го казва направо. Ако проектът има само src/main.rs, не можеш да създадеш интеграционни тестове в tests/, които да импортират функциите му, защото «Only library crates expose functions that other crates can use; binary crates are meant to be run on their own» [1]: двоичните файлове са направени да се изпълняват сами.
И дава изхода в същия абзац: прост src/main.rs, който извиква логиката от src/lib.rs [1]. Глава 12 превръща това в рецепта и оставя на main малко: да прочете аргументите, да подготви конфигурацията, да извика библиотеката и да обработи грешката [2].
Измерено на проект с една функция: в main.rs, частна или pub, тестът дава E0432; в lib.rs и pub — минава.
Шаблонът от тази част, estructura-rust, е направен така:
estructura-rust/
├── Cargo.toml · Cargo.lock
├── servicios.yaml el ejemplo
├── src/
│ ├── main.rs EL PROGRAMA: opciones, llamada, código de salida
│ ├── lib.rs LA BIBLIOTECA: declara los módulos y qué es público
│ ├── servicio.rs el vocabulario. Sin red ni archivos
│ ├── config.rs lee y valida servicios.yaml
│ ├── revisar.rs consulta muchos servicios a la vez
│ └── reporte.rs tabla y JSON
├── tests/ cada archivo es un crate aparte
│ ├── integracion.rs
│ ├── binario.rs
│ └── comun/mod.rs
├── herramientas/probar-frontera.sh
├── .github/workflows/verificar.yml
└── README.md · LICENSE · LICENSE-CONTENIDO.mdДа минем част по част, с обичайния въпрос: какъв проблем решава днес?
Защо в src/ има два корена?
lib.rs е библиотеката, а main.rs е програмата: два crate-а от един и същ пакет, и Cargo намира и двата, без да го молиш.
Това са пътищата по конвенция на Cargo: библиотеката в src/lib.rs, изпълнимият файл в src/main.rs и интеграционните тестове в tests/ [6]. Затова Cargo.toml не обявява нито един от тях.
Интересното е как си говорят. Програмата е просто още един потребител на библиотеката, като външен crate: «It can only use the public API» [3]. main.rs има същите права като tests/ и като всеки чужд проект, а книгата вижда в това предимство: като си едновременно автор и клиент, проектираш по-добре API-то си [3].
Какво прави тогава main.rs?
Минимумът, който една програма не може да делегира: да прочете опциите, да извика и да реши с какъв код да завърши.
В шаблона main.rs чете три опции, извиква библиотеката, отпечатва отчета и излиза с 0, 1 или 2. Не решава какво е здрава услуга. Останалото се тества, като програмата се изпълни цялата: когато има интеграционни тестове, Cargo компилира програмата предварително и оставя пътя ѝ в CARGO_BIN_EXE_<nombre> [7]. Така работи tests/binario.rs. Това, което е в main.rs, не може да се импортира отвън; да се изпълни — може.
Какво означава, че всичко е частно?
Че нищо не се вижда извън модула, в който се ражда, освен от подмодулите му, докато не му сложиш pub; и компилаторът следи това да се спазва.
Rust Book го казва със списък: в Rust всички елементи (функции, методи, структури, enum-и, модули и константи) «are private to parent modules by default» [3]. Справочникът на езика го обобщава: «By default, everything is private», с две изключения, които тук не са от значение [5].
Защо така? За да знаеш кои части можеш да промениш, без да счупиш външния код, казва книгата [3]. И нарича публичното API на библиотеката ти «your contract with users of your crate» [3]: договорът ти с тези, които я ползват.
Има и средно положение, pub(crate): видимо в целия текущ crate [5]. То подвежда, защото тест в tests/ е друг crate (измерено: дава същата грешка като частното).
В шаблона reporte.rs предлага две публични функции, tabla и json. Тази, която чисти URL адреса, url_publica, е частна: тя е подробност от това как се сглобява отчетът.
Тогава как се тества url_publica?
Отвътре: модулните тестове живеят в същия файл и виждат частното.
Конвенцията на книгата е модул tests в края на всеки файл от src/, отбелязан с #[cfg(test)], за да се компилира само с cargo test [1]. Той е дъщерен подмодул на файла, а «items in child modules can use the items in their ancestor modules» [1]: дъщерният модул вижда частното на предците си. Затова «Rust’s privacy rules do allow you to test private functions» [1]. Разпределението в шаблона:
| Къде | Какво вижда | Какво тества |
|---|---|---|
В края на servicio.rs, config.rs и reporte.rs | Всичко, включително частното | Всяко парче поотделно: url_publica, clasificar, грешките на config |
tests/integracion.rs | Само pub от библиотеката | Парчетата заедно, срещу локален HTTP сървър |
tests/binario.rs | Програмата, като процес | Какво отпечатва и с какъв код излиза |
Документацията на servicio.rs | pub | Че примерът на clasificar продължава да е верен |
Последното заслужава един ред. Примерът в коментара на clasificar също е тест: cargo test изважда примерите от документацията на библиотеката и ги изпълнява [8]. Тези на програмата — не: измерено с нарочно грешен пример, в main.rs никой не го пуска и всичко излиза зелено; в lib.rs същият пример става червен. Още една причина логиката да живее в lib.rs.
Ето как изглежда cargo test --locked в шаблона, само редовете, които имат значение (пътищата са съкратени; времената се менят):
Running unittests src/lib.rs (…)
test result: ok. 28 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/main.rs (…)
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running tests/binario.rs (…)
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.33s
Running tests/integracion.rs (…)
test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.13s
Doc-tests revisor
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sТова са 49 теста в пет блока. Броят се там, в редовете test result, а не по кода на изход: ако файл от tests/ не се компилира, блокът му дори не се появява.
Защо tests/comun/mod.rs, а не tests/comun.rs?
Защото всеки файл в корена на tests/ е отделен набор тестове, а файл с помощни функции би излизал като празен набор при всяко изпълнение.
Двата интеграционни теста споделят тестов HTTP сървър на 127.0.0.1. Ако той живееше в tests/comun.rs, Cargo щеше да го компилира като още един набор [1] и той щеше да излиза при всяко изпълнение с running 0 tests (измерено). Книгата показва този случай и казва, че това «is not what we wanted» [1]. Изходът ѝ е този на шаблона: подпапка, защото файловете в подпапките на tests/ не се компилират като отделни crate-ове [1]. Всеки тест я включва с mod comun;.
А модулите в src/, без mod.rs?
По един файл за модул, с името на модула. Това е пътят, който книгата нарича по-идиоматичен.
Всеки ред pub mod reporte; в lib.rs казва на компилатора да търси src/reporte.rs. Rust Book учи този път и признава и един по-стар, src/reporte/mod.rs, който още работи [4]. Кой е за предпочитане и какво става, ако се смесят, е в грешка 3.
За какво се грижи revisar.rs, което един шаблон не бива да учи погрешно?
Времеви лимит, който покрива цялата заявка, таван за прочетеното и грешки, които никога не повтарят URL адреса.
Времевият лимит обхваща цялата заявка, от името на сървъра до тялото, а от тялото се четат най-много 64 KiB. Една измерена тънкост: ако сървърът за имена не отговаря, отчетът излиза навреме, но програмата приключва чак когато системата се откаже (в Linux — около 10 s). Грешките на reqwest, HTTP библиотеката, «may include the full URL», предупреждава документацията ѝ [12]; шаблонът никога не ползва техния текст. Нито този на грешките от YAML, които повтарят стойността (измерено): казва услугата, полето и, ако YAML файлът не може да се прочете, реда и колоната. Махнахме всяка защита в копие, една по една: и десетте станаха червени. А границите (кодът 400, --paralelo 0, 1 и 60 000 ms) имат свой тест, който става червен, ако границата се премести.
А къде отива поправката на Иван?
В библиотеката, в reporte.rs, до този, който я ползва; а тестът ѝ — в края на същия файл.
В сряда Иван и Лусия разделиха main.rs. Функцията за URL адреса остана в reporte.rs, частна, с модулния си тест до нея. Тестът, който Иван искаше, «токенът не излиза», остана в tests/, но ползва публичната функция json. Отвън се тества обещаното; отвътре — как се изпълнява.
Как разбирам, че границата съществува?
Защото един скрипт я преминава нарочно при всяка промяна и изисква компилаторът да я отхвърли по точната причина.
herramientas/probar-frontera.sh работи върху временно копие. Засажда tests/frontera.rs, тест, който извиква revisor::reporte::url_publica, и го компилира два пъти върху същото копие. Между двата пъти се сменя само една дума в src/reporte.rs — pub:
- Контрола, с
pub fn url_publica. Тестът трябва да се компилира и да мине. Ако не, експериментът е зле подготвен (функцията е сменила името си, засаденият тест има грешка) и скриптът спира в червено. - Нарушение, със
src/reporte.rsтакъв, какъвто е. Същият тест трябва да не се компилира, с грешкатаE0603, в теста, а не в библиотеката.
Ето истинския изход:
1/2 control: con «pub fn url_publica», una prueba de tests/ la llama
✅ compiló y pasó (1 de 1): la prueba sembrada está bien escrita
2/2 violación: la misma prueba, con src/reporte.rs tal como está
error[E0603]: function `url_publica` is private
--> tests/frontera.rs:6:27
✅ el compilador la rechazó: lo que no es pub no se ve desde tests/
✅ frontera: se sostieneЗащо контролата? Защото експеримент, който очаква само червено, става «зелен» и когато се провали по грешната причина. Счупихме го по четири начина: с преименувана функция или зле написан засаден тест спира на «el control NO pasó»; с друг очакван код на грешка казва, че се е провалил, «pero NO por la privacidad»; с функцията като pub казва ❌ COMPILÓ. С pub(crate) границата издържа.
CI в GitHub е написан да пуска форматирането, clippy, тестовете и границата със стабилния Rust и с 1.85.0, а границата — и в macOS със системния /bin/bash, при всяка промяна и всеки понеделник. Шаблонът вече е публикуван в GitHub. Ако той остане 60 дни без активност, GitHub изключва понеделнишкото изпълнение [20].
Кои са пет чести грешки?
Първите две идват от това, че не знаеш какво вижда tests/; третата — от смесването на стилове; последните две — от това, че отваряш повече от нужното: API-то или проекта.
1. Всичко в main.rs, без lib.rs
Работи, но от tests/ нищо не може да се импортира, дори с pub.
Това е грешката на Иван [1]. Глава 12 дава дълбоката причина: тъй като не можеш да тестваш функцията main пряко, изваждането на логиката от нея ти позволява да тестваш цялата логика, а остатъкът се проверява с четене [2]. Издава я E0432, с подсказка за cargo add, която сочи на друго място (измерено). Не ти трябва друг пакет: трябва ти твоята библиотека.
2. Помощните функции за тестове в tests/common.rs
Cargo го компилира като още един набор тестове и той излиза празен при всяко изпълнение.
Книгата го показва: tests/common.rs се появява с running 0 tests, макар да няма тестове [1]. Нищо не чупи, но цапа преброяването. Изходът е подпапката, tests/common/mod.rs [1].
3. Смесване на mod.rs с файлове, които носят името на модула
За един и същ модул компилаторът спира; за различни модули се компилира, но обърква.
Rust Book различава два случая. Ако ползваш двата стила за един и същ модул, «you’ll get a compiler error» [4]. Измерено в шаблона, със src/reporte.rs и src/reporte/mod.rs едновременно:
error[E0761]: file for module `reporte` found at both "src/reporte.rs" and "src/reporte/mod.rs"При различни модули се компилира, но «might be confusing for people navigating your project» [4], а с mod.rs накрая имаш много еднакво наречени файлове, отворени в редактора [4]. Избери един стил; шаблонът ползва този, който книгата нарича по-идиоматичен.
4. pub на всичко, защото компилаторът се оплаква
Всяко pub разширява това, което другите могат да ползват, и компилаторът престава да те предупреждава, ако е излишно.
Пред E0603 първо се запитай кой има нужда от тази функция. Ако е тест, той отива в края на файла, като модулен тест [1]. Ако е друг модул от същия crate, стига pub(crate) [5].
Ако публикуваш библиотеката или друг пакет я ползва, цената е записана в ръководството за съвместимост на Cargo, което разглежда новите версии на един пакет: «Major: renaming/moving/removing any public items» [11]. Шаблонът не се публикува (publish = false): това, което е pub, се ползва само от main.rs и tests/, които се поправят в същата промяна. Въпреки това има измерена цена: pub изключва предупреждението за мъртъв код. С pub(crate) и без употреба компилаторът казва `warning: function url_publica is never used; с pub мълчи. Затова границата в шаблона става червена, ако url_publica стане pub`.
5. Да не версионираш Cargo.lock, когато CI има нужда от него, или да направиш workspace преждевременно
Първото те оставя без запис с какво е тествано; второто — със структура, за която още няма нужда.
FAQ на Cargo казва, че Cargo.lock записва състоянието на компилация, която е проработила, за да се повтори същата по друго време и на друга машина, и че така CI се проваля само заради нови промени, а не заради външни фактори [9]. cargo new го версионира по подразбиране; FAQ уточнява, че зависи от това, от какво има нужда пакетът ти [9]. Сред употребите посочва една, която шаблонът прави с реда 1.85.0 в CI: «Verifying a minimum-supported Rust version (MSRV) that is less than the latest version of a dependency supports» [9]. И предупреждава за границата: този детерминизъм «can give a false sense of security», защото Cargo.lock не засяга този, който ползва пакета ти [9]. Шаблонът тръгва с --locked, който се проваля, ако файлът липсва или ако cargo иска да го промени [8]. Измерено, без Cargo.lock:
error: cannot create the lock file …/Cargo.lock because --locked was passed to prevent thisДругата крайност е workspace от първия ден: група пакети, които споделят Cargo.lock и папка за компилация [10] и които Rust Book представя за момента, когато проектът вече е пораснал и искаш да го разделиш на няколко crate-а [10]. С един пакет няма какво да се споделя.
| Грешка | Какво я издава | Източник |
|---|---|---|
1. Всичко в main.rs | E0432: unresolved import от tests/ | [1][2] |
2. Помощни функции в tests/common.rs | Набор с running 0 tests | [1] |
3. mod.rs и файл с името на модула | E0761: file for module … found at both | [4] |
4. pub на всичко | Никакво предупреждение never used; ако публикуваш, всяко премахване е голяма промяна | [3][11] |
5. Без Cargo.lock при CI, който има нужда от него, или workspace с един пакет | cannot create the lock file с --locked; структура, която нищо не ползва | [8][9][10] |
Упражнение: можеш ли да преминеш границата?
Ще опиташ да ползваш частна функция от tests/, ще видиш колко трябва да отвориш, за да успееш, и ще видиш как скриптът те предупреждава, че си отворил повече от нужното.
Трябват ти Rust 1.85 или по-нов (cargo --version), инсталиран с rustup, плюс Git и bash; около 20 минути, плюс няколко минути първия път, докато се компилират зависимостите.
- В Linux Mint 22 не ползвай
apt install cargo: Mint 22 е базиран на Ubuntu 24.04 [16], който идва с Rust 1.75 [15], а изданието 2024 дойде с 1.85 [18]. Измерено с този cargo: `featureedition2024is required, плюс предложение да добавишcargo-featuresвCargo.toml. Не го следвай: обнови Rust. Ако вече си го инсталирал сapt, махни го съсsudo apt remove cargo rustc; иначе инсталаторът наrustupте предупреждава, че вече има Rust в/usr/bin(измерено). После пусниsudo apt install build-essential curlи командата наrustup` [13][14]:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shБез build-essential излиза `error: linker cc not found` (измерено). Урок 0 от курса по Rust го обяснява стъпка по стъпка. - В macOS — xcode-select --install и после същата команда на rustup [13]. - Ако вече имаш rustup — rustup update stable. В Windows ползвай WSL. - Накрая отвори друг терминал и провери, че cargo --version показва 1.85 или повече: в същия терминал cargo още не се намира или си остава старият (измерено).
Стъпка 1. Клонирай и провери, че всичко е зелено.
git clone https://github.com/HabilMX/estructura-rust
cd estructura-rust
cargo test --locked
bash herramientas/probar-frontera.shКакво трябва да видиш: пет реда test result: ok., които дават общо 49 теста, и в края на скрипта ✅ frontera: se sostiene.
Стъпка 2. Предскажи, преди да пипнеш. Ще напишеш тест в tests/, който извиква url_publica, а тя е частна. Запиши три неща: компилира ли се така? А ако я направиш pub(crate)? А ако я направиш pub?
Стъпка 3. Опитай да преминеш.
cat > tests/mia.rs <<'EOF'
#[test]
fn quita_el_token() {
assert_eq!(
revisor::reporte::url_publica("https://pagos.ejemplo.com/salud?token=x"),
"https://pagos.ejemplo.com/salud"
);
}
EOF
cargo test --locked --test miaНе се компилира. Първият ред от грешката:
error[E0603]: function `url_publica` is privateСтъпка 4. Отвори я за crate-а. Копирай само реда със sed за твоята система: този за macOS иска празен аргумент след -i (ако на твоя Mac sed е този на GNU, ползвай реда за Linux).
# En Linux:
sed -i 's/^fn url_publica(/pub(crate) fn url_publica(/' src/reporte.rs
# En macOS:
sed -i '' 's/^fn url_publica(/pub(crate) fn url_publica(/' src/reporte.rs
cargo test --locked --test miaСъщото E0603. pub(crate) отваря функцията за целия crate на библиотеката, а твоят тест е друг crate.
Стъпка 5. Отвори я докрай.
# En Linux:
sed -i 's/^pub(crate) fn url_publica(/pub fn url_publica(/' src/reporte.rs
# En macOS:
sed -i '' 's/^pub(crate) fn url_publica(/pub fn url_publica(/' src/reporte.rs
cargo test --locked --test mia
bash herramientas/probar-frontera.shТестът ти минава (test result: ok. 1 passed). Но скриптът става червен:
❌ COMPILÓ: una prueba de tests/ pudo llamar a revisor::reporte::url_publica. La frontera no existe.Успя да я ползваш отвън и с това я вкара в договора си. Това е контролата в действие.
Стъпка 6. Върни всичко както беше.
git checkout -- . && git clean -fd
bash herramientas/probar-frontera.shВнимавай: git clean -fd изтрива и новите файлове, които си създал там, например бележките си.
Как разбираш, че си се справил: пусна седем пъти и видя три резултата. Зелено, четири пъти: двата в стъпка 1, твоят тест в стъпка 5 и границата в стъпка 6. Червено E0603, два пъти: стъпки 3 и 4. И червеното «COMPILÓ» на скрипта в стъпка 5. Ако в стъпка 4 тестът ти се компилира, провери дали не си написал pub вместо pub(crate). Ако в стъпка 5 E0603 остава, редът със sed не е намерил pub(crate) fn url_publica(: прегледай стъпка 4.
За по-нататък (по желание): премести tests/comun/mod.rs в tests/comun.rs (изтрий празната папка) и пусни cargo test --locked. Преди това предскажи колко блока test result ще видиш. Отговор: шест, с един повече от преди, Running tests/comun.rs с running 0 tests (измерено). Върни се със същото git checkout -- . && git clean -fd.
Ключови изводи
Три въпроса, които да зададеш на своето хранилище тази седмица.
- Има ли проектът ти
src/lib.rs? Ако няма, коя функция отmain.rsби искал да тестваш отвън и днес не можеш? - От това, което е
pubв библиотеката ти, какво наистина ползва друг crate? Това, което никой не ползва отвън, може ли да е частно илиpub(crate)? - Пуска ли се CI-ят ти с
--locked? Ако не, с кои версии на зависимостите ти е тестван последният зелен резултат?
Какво следва?
В Go границата я пази инструментът; в Python — инсталацията; в Rust — компилаторът. В TypeScript има една, която редакторът приема, а Node никога не вижда.
Седмица по-късно Иван наследи API на TypeScript. Един import с хубав псевдоним, @/revisar, се компилираше без нито едно оплакване. Редакторът го допълваше сам.
Node, при стартиране, не го намери.
Как може да се компилира програма, която не тръгва? В неделя, 22 ноември, в част 4: какво решава tsconfig.json, какво не решава и защо тестовете и кодът се компилират поотделно.
Шаблонът и курсът
- Шаблон: github.com/HabilMX/estructura-rust. Използва се като шаблон в GitHub или се клонира [19]. README-то обяснява всяка папка, какво не включва, кога да добавиш всяко нещо и как да махнеш примера. Кодът е под MIT; текстът и обясненията — под CC BY-SA 4.0.
- Версии: издание 2024 и
rust-version = "1.85", първата версия с това издание [18]. Тестван е с Rust 1.99.1, стабилната към 22 октомври [17], в macOS arm64 (и със системния/bin/bash) и в Linux arm64 (контейнерubuntu:24.04), както и с 1.85.0 в macOS arm64. Linux x86-64 още не е тестван. CI е написан за стабилната версия на всяка седмица и 1.85.0 в Linux, и стабилната в macOS [21]. Зависимостите са фиксирани вCargo.lock. - Курсът по Rust на Hábil: ако модулите,
pubили интеграционните тестове са нови за теб, урок 6 ги обяснява от нулата: Курс по Rust · Урок 6, Модули, тестове и Cargo.
Пиша от това, което виждаме всеки ден в Hábil, където изграждаме системи за банки, застраховане и компании в Мексико. Ако в работата или в университета ти и колегите ти попаднете на хранилище, за което никой не знае откъде да го хване, да поговорим: habil.mx
Какво прави Hábil?
Учим на програмиране със същото, с което изграждаме: тестван, обяснен и отворен код.
Тази поредица идва от същото място като нашите курсове. Курсът по Rust е вторият, след Go: учи чии са данните и кои грешки компилаторът хваща преди изпълнение, и го публикуваме отворено, с лиценз Creative Commons; урок 6 обяснява модулите, тестовете и Cargo, които използва шаблонът от тази статия. А в каталога има още курсове по програмиране, безплатни и с тестван и обяснен стъпка по стъпка код.
Разгледай Курса по Rust и каталога Курсове по програмиране.
Ако екипът ти наследи система, за която никой не знае откъде да я хване, или трябва да изгради такава, която да може да се поддържа и занапред, правим и това: разгледай Изграждане на система по поръчка. Поискай първи разговор, без заплащане. В него преглеждаме дали си струва да се настрои това, което екипът ти вече има, да се ползва продукт или да се изгради, и какво би получил екипът във всеки случай. Пиши ни в WhatsApp.
Източниците са проверени на 22 октомври 2026 г. Цитатите на английски са възпроизведени дословно.
Източници
- Steve Klabnik, Carol Nichols и Chris Krycho, «Test Organization» (11.3), The Rust Programming Language. https://doc.rust-lang.org/book/ch11-03-test-organization.html
- Steve Klabnik, Carol Nichols и Chris Krycho, «Refactoring to Improve Modularity and Error Handling» (12.3): «Separation of Concerns for Binary Projects», The Rust Programming Language. https://doc.rust-lang.org/book/ch12-03-improving-error-handling-and-modularity.html
- Steve Klabnik, Carol Nichols и Chris Krycho, «Paths for Referring to an Item in the Module Tree» (7.3), включително «Best Practices for Packages with a Binary and a Library», The Rust Programming Language. https://doc.rust-lang.org/book/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html
- Steve Klabnik, Carol Nichols и Chris Krycho, «Separating Modules into Different Files» (7.5): «Alternate File Paths», The Rust Programming Language. https://doc.rust-lang.org/book/ch07-05-separating-modules-into-different-files.html
- The Rust Reference, «Visibility and privacy». https://doc.rust-lang.org/reference/visibility-and-privacy.html
- The Cargo Book, «Package Layout». https://doc.rust-lang.org/cargo/guide/project-layout.html
- The Cargo Book, «Cargo Targets»: «Binaries» и «Integration tests». https://doc.rust-lang.org/cargo/reference/cargo-targets.html
- The Cargo Book, «cargo test»: «Documentation tests» и
--locked. https://doc.rust-lang.org/cargo/commands/cargo-test.html - The Cargo Book, «Frequently Asked Questions»: «Why have Cargo.lock in version control?». https://doc.rust-lang.org/cargo/faq.html
- Steve Klabnik, Carol Nichols и Chris Krycho, «Cargo Workspaces» (14.3), The Rust Programming Language. https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html
- The Cargo Book, «SemVer Compatibility». https://doc.rust-lang.org/cargo/reference/semver.html
- reqwest 0.13.5, «Struct Error», docs.rs. https://docs.rs/reqwest/0.13.5/reqwest/struct.Error.html
- Steve Klabnik, Carol Nichols и Chris Krycho, «Installation» (1.1), The Rust Programming Language. https://doc.rust-lang.org/book/ch01-01-installation.html
- The Rust Project, «Install Rust», rust-lang.org. https://www.rust-lang.org/tools/install
- Launchpad (Canonical), пакет
rustc, публикуван в Ubuntu 24.04 «noble»: 1.75.0. https://api.launchpad.net/1.0/ubuntu/+archive/primary?ws.op=getPublishedSources&source_name=rustc&exact_match=true&distro_series=https://api.launchpad.net/1.0/ubuntu/noble - Linux Mint, «Linux Mint 22 Release Notes» («Linux Mint 22.x is based on Ubuntu 24.04»), linuxmint.com. https://www.linuxmint.com/rel_wilma.php
- The Rust Release Team, «Announcing Rust 1.99.1», Rust Blog, 15 октомври 2026 г. https://blog.rust-lang.org/2026/10/15/Rust-1.99.1/
- The Rust Release Team, «Announcing Rust 1.85.0 and Rust 2024», Rust Blog, 20 февруари 2025 г. https://blog.rust-lang.org/2025/02/20/Rust-1.85.0/
- GitHub Docs, «Creating a template repository». https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository
- GitHub Docs, «Disabling and enabling a workflow». https://docs.github.com/en/actions/how-tos/manage-workflow-runs/disable-and-enable-workflows
- David Tolnay, «dtolnay/rust-toolchain», README, GitHub. https://github.com/dtolnay/rust-toolchain
Вашата дейност среща ли тези предизвикателства?
Предпочитате имейл? Пишете ни на hola@habil.mx