Compare commits
1 commit
main
...
rustlings-
Author | SHA1 | Date | |
---|---|---|---|
|
8597f54a11 |
178 changed files with 2604 additions and 8453 deletions
1049
.all-contributorsrc
1049
.all-contributorsrc
File diff suppressed because it is too large
Load diff
|
@ -1,4 +0,0 @@
|
|||
[clog]
|
||||
|
||||
repository = "https://github.com/rust-lang/rustlings"
|
||||
changelog = "CHANGELOG.md"
|
|
@ -1,7 +0,0 @@
|
|||
root = true
|
||||
|
||||
[*.rs]
|
||||
end_of_line = lf
|
||||
insert_final_newfile = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -1,10 +1,2 @@
|
|||
*.swp
|
||||
target/
|
||||
**/*.rs.bk
|
||||
.DS_Store
|
||||
*.pdb
|
||||
exercises/clippy/Cargo.toml
|
||||
exercises/clippy/Cargo.lock
|
||||
.idea
|
||||
.vscode
|
||||
*.iml
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
tasks:
|
||||
- init: /workspace/rustlings/install.sh
|
||||
command: /workspace/.cargo/bin/rustlings watch
|
||||
|
||||
vscode:
|
||||
extensions:
|
||||
- rust-lang.rust@0.7.8:CvNqMTgDdt3UXt+6BCDTVg==
|
2
.replit
2
.replit
|
@ -1,2 +0,0 @@
|
|||
language = "rust"
|
||||
run = "[ -x ~/.cargo/bin/rustlings ] && ~/.cargo/bin/rustlings watch || ./install.sh"
|
19
.travis.yml
Normal file
19
.travis.yml
Normal file
|
@ -0,0 +1,19 @@
|
|||
language: rust
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
cache:
|
||||
cargo: true
|
||||
|
||||
script:
|
||||
- cargo run --bin generate_readme
|
||||
- git config user.name "Carol (Nichols || Goulding)"
|
||||
- git config user.email "carol.nichols@gmail.com"
|
||||
- git commit -am "Regenerate README" && git remote add upstream "https://$GH_TOKEN@github.com/carols10cents/rustlings.git" && git push -q upstream HEAD:master > /dev/null 2>&1 || true
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
|
446
CHANGELOG.md
446
CHANGELOG.md
|
@ -1,446 +0,0 @@
|
|||
<a name="4.6.0"></a>
|
||||
## 4.6.0 (2021-09-25)
|
||||
|
||||
|
||||
#### Features
|
||||
|
||||
* add advanced_errs2 ([abd6b70c](https://github.com/rust-lang/rustlings/commit/abd6b70c72dc6426752ff41f09160b839e5c449e))
|
||||
* add advanced_errs1 ([882d535b](https://github.com/rust-lang/rustlings/commit/882d535ba8628d5e0b37e8664b3e2f26260b2671))
|
||||
* Add a farewell message when quitting `watch` ([1caef0b4](https://github.com/rust-lang/rustlings/commit/1caef0b43494c8b8cdd6c9260147e70d510f1aca))
|
||||
* add more watch commands ([a7dc080b](https://github.com/rust-lang/rustlings/commit/a7dc080b95e49146fbaafe6922a6de2f8cb1582a), closes [#842](https://github.com/rust-lang/rustlings/issues/842))
|
||||
* **modules:** update exercises, add modules3 (#822) ([dfd2fab4](https://github.com/rust-lang/rustlings/commit/dfd2fab4f33d1bf59e2e5ee03123c0c9a67a9481))
|
||||
* **quiz1:** add default function name in comment (#838) ([0a11bad7](https://github.com/rust-lang/rustlings/commit/0a11bad71402b5403143d642f439f57931278c07))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Correct small typo in exercises/conversions/from_str.rs ([86cc8529](https://github.com/rust-lang/rustlings/commit/86cc85295ae36948963ae52882e285d7e3e29323))
|
||||
* **cli:** typo in exercise.rs (#848) ([06d5c097](https://github.com/rust-lang/rustlings/commit/06d5c0973a3dffa3c6c6f70acb775d4c6630323c))
|
||||
* **from_str, try_from_into:** custom error types ([2dc93cad](https://github.com/rust-lang/rustlings/commit/2dc93caddad43821743e4903d89b355df58d7a49))
|
||||
* **modules2:** fix typo (#835) ([1c3beb0a](https://github.com/rust-lang/rustlings/commit/1c3beb0a59178c950dc05fe8ee2346b017429ae0))
|
||||
* **move_semantics5:**
|
||||
* change &mut *y to &mut x (#814) ([d75759e8](https://github.com/rust-lang/rustlings/commit/d75759e829fdcd64ef071cf4b6eae2a011a7718b))
|
||||
* Clarify instructions ([df25684c](https://github.com/rust-lang/rustlings/commit/df25684cb79f8413915e00b5efef29369849cef1))
|
||||
* **quiz1:** Fix inconsistent wording (#826) ([03131a3d](https://github.com/rust-lang/rustlings/commit/03131a3d35d9842598150f9da817f7cc26e2669a))
|
||||
|
||||
|
||||
|
||||
<a name="4.5.0"></a>
|
||||
## 4.5.0 (2021-07-07)
|
||||
|
||||
|
||||
#### Features
|
||||
|
||||
* Add move_semantics5 exercise. (#746) ([399ab328](https://github.com/rust-lang/rustlings/commit/399ab328d8d407265c09563aa4ef4534b2503ff2))
|
||||
* **cli:** Add "next" to run the next unsolved exercise. (#785) ([d20e413a](https://github.com/rust-lang/rustlings/commit/d20e413a68772cd493561f2651cf244e822b7ca5))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* rename result1 to errors4 ([50ab289d](https://github.com/rust-lang/rustlings/commit/50ab289da6b9eb19a7486c341b00048c516b88c0))
|
||||
* move_semantics5 hints ([1b858285](https://github.com/rust-lang/rustlings/commit/1b85828548f46f58b622b5e0c00f8c989f928807))
|
||||
* remove trailing whitespaces from iterators1 ([4d4fa774](https://github.com/rust-lang/rustlings/commit/4d4fa77459392acd3581c6068aa8be9a02de12fc))
|
||||
* add hints to generics1 and generics2 exercises ([31457940](https://github.com/rust-lang/rustlings/commit/31457940846b3844d78d4a4d2b074bc8d6aaf1eb))
|
||||
* remove trailing whitespace ([d9b69bd1](https://github.com/rust-lang/rustlings/commit/d9b69bd1a0a7a99f2c0d80933ad2eea44c8c71b2))
|
||||
* **installation:** first PowerShell command ([aa9a943d](https://github.com/rust-lang/rustlings/commit/aa9a943ddf3ae260782e73c26bcc9db60e5894b6))
|
||||
* **iterators5:** derive Clone, Copy ([91fc9e31](https://github.com/rust-lang/rustlings/commit/91fc9e3118f4af603c9911698cc2a234725cb032))
|
||||
* **quiz1:** Updated question description (#794) ([d8766496](https://github.com/rust-lang/rustlings/commit/d876649616cc8a8dd5f539f8bc1a5434b960b1e9))
|
||||
* **try_from_into, from_str:** hints for dyn Error ([11d2cf0d](https://github.com/rust-lang/rustlings/commit/11d2cf0d604dee3f5023c17802d69438e69fa50e))
|
||||
* **variables5:** confine the answer further ([48ffcbd2](https://github.com/rust-lang/rustlings/commit/48ffcbd2c4cc4d936c2c7480019190f179813cc5))
|
||||
|
||||
|
||||
|
||||
<a name="4.4.0"></a>
|
||||
## 4.4.0 (2021-04-24)
|
||||
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Fix spelling error in main.rs ([91ee27f2](https://github.com/rust-lang/rustlings/commit/91ee27f22bd3797a9db57e5fd430801c170c5db8))
|
||||
* typo in default out text ([644c49f1](https://github.com/rust-lang/rustlings/commit/644c49f1e04cbb24e95872b3a52b07d692ae3bc8))
|
||||
* **collections:** Naming exercises for vectors and hashmap ([bef39b12](https://github.com/rust-lang/rustlings/commit/bef39b125961310b34b34871e480a82e82af4678))
|
||||
* **from_str:**
|
||||
* Correct typos ([5f7c89f8](https://github.com/rust-lang/rustlings/commit/5f7c89f85db1f33da01911eaa479c3a2d4721678))
|
||||
* test for error instead of unwrap/should_panic ([15e71535](https://github.com/rust-lang/rustlings/commit/15e71535f37cfaed36e22eb778728d186e2104ab))
|
||||
* use trait objects for from_str ([c3e7b831](https://github.com/rust-lang/rustlings/commit/c3e7b831786c9172ed8bd5d150f3c432f242fba9))
|
||||
* **functions3:** improve function argument type (#687) ([a6509cc4](https://github.com/rust-lang/rustlings/commit/a6509cc4d545d8825f01ddf7ee37823b372154dd))
|
||||
* **hashmap2:** Update incorrect assertion (#660) ([72aaa15e](https://github.com/rust-lang/rustlings/commit/72aaa15e6ab4b72b3422f1c6356396e20a2a2bb8))
|
||||
* **info:** Fix typo (#635) ([cddc1e86](https://github.com/rust-lang/rustlings/commit/cddc1e86e7ec744ee644cc774a4887b1a0ded3e8))
|
||||
* **iterators2:** Moved errors out of tests. ([baf4ba17](https://github.com/rust-lang/rustlings/commit/baf4ba175ba6eb92989e3dd54ecbec4bedc9a863), closes [#359](https://github.com/rust-lang/rustlings/issues/359))
|
||||
* **iterators3:** Enabled iterators3.rs to run without commented out tests. ([c6712dfc](https://github.com/rust-lang/rustlings/commit/c6712dfccd1a093e590ad22bbc4f49edc417dac0))
|
||||
* **main:** Let find_exercise work with borrows ([347f30bd](https://github.com/rust-lang/rustlings/commit/347f30bd867343c5ace1097e085a1f7e356553f7))
|
||||
* **move_semantics4:**
|
||||
* Remove redundant "instead" (#640) ([cc266d7d](https://github.com/rust-lang/rustlings/commit/cc266d7d80b91e79df3f61984f231b7f1587218e))
|
||||
* Small readbility improvement (#617) ([10965920](https://github.com/rust-lang/rustlings/commit/10965920fbdf8a1efc85bed869e55a1787006404))
|
||||
* **option2:** Rename uninformative variables (#675) ([b4de6594](https://github.com/rust-lang/rustlings/commit/b4de6594380636817d13c2677ec6f472a964cf43))
|
||||
* **quiz3:** Force an answer to Q2 (#672) ([0d894e6f](https://github.com/rust-lang/rustlings/commit/0d894e6ff739943901e1ae8c904582e5c2f843bd))
|
||||
* **structs:** Add 5.3 to structs/README (#652) ([6bd791f2](https://github.com/rust-lang/rustlings/commit/6bd791f2f44aa7f0ad926df767f6b1fa8f12a9a9))
|
||||
* **structs2:** correct grammar in hint (#663) ([ebdb66c7](https://github.com/rust-lang/rustlings/commit/ebdb66c7bfb6d687a14cc511a559a222e6fc5de4))
|
||||
* **structs3:**
|
||||
* reword heading comment (#664) ([9f3e8c2d](https://github.com/rust-lang/rustlings/commit/9f3e8c2dde645e5264c2d2200e68842b5f47bfa3))
|
||||
* add check to prevent naive implementation of is_international ([05a753fe](https://github.com/rust-lang/rustlings/commit/05a753fe6333d36dbee5f68c21dec04eacdc75df))
|
||||
* **threads1:** line number correction ([7857b0a6](https://github.com/rust-lang/rustlings/commit/7857b0a689b0847f48d8c14cbd1865e3b812d5ca))
|
||||
* **try_from_into:** use trait objects ([2e93a588](https://github.com/rust-lang/rustlings/commit/2e93a588e0abe8badb7eafafb9e7d073c2be5df8))
|
||||
|
||||
#### Features
|
||||
|
||||
* Replace clap with argh ([7928122f](https://github.com/rust-lang/rustlings/commit/7928122fcef9ca7834d988b1ec8ca0687478beeb))
|
||||
* Replace emojis when NO_EMOJI env variable present ([8d62a996](https://github.com/rust-lang/rustlings/commit/8d62a9963708dbecd9312e8bcc4b47049c72d155))
|
||||
* Added iterators5.rs exercise. ([b29ea17e](https://github.com/rust-lang/rustlings/commit/b29ea17ea94d1862114af2cf5ced0e09c197dc35))
|
||||
* **arc1:** Add more details to description and hint (#710) ([81be4044](https://github.com/rust-lang/rustlings/commit/81be40448777fa338ebced3b0bfc1b32d6370313))
|
||||
* **cli:** Improve the list command with options, and then some ([8bbe4ff1](https://github.com/rust-lang/rustlings/commit/8bbe4ff1385c5c169c90cd3ff9253f9a91daaf8e))
|
||||
* **list:**
|
||||
* updated progress percentage ([1c6f7e4b](https://github.com/rust-lang/rustlings/commit/1c6f7e4b7b9b3bd36f4da2bb2b69c549cc8bd913))
|
||||
* added progress info ([c0e3daac](https://github.com/rust-lang/rustlings/commit/c0e3daacaf6850811df5bc57fa43e0f249d5cfa4))
|
||||
|
||||
|
||||
|
||||
<a name="4.3.0"></a>
|
||||
## 4.3.0 (2020-12-29)
|
||||
|
||||
#### Features
|
||||
|
||||
* Rewrite default out text ([44d39112](https://github.com/rust-lang/rustlings/commit/44d39112ff122b29c9793fe52e605df1612c6490))
|
||||
* match exercise order to book chapters (#541) ([033bf119](https://github.com/rust-lang/rustlings/commit/033bf1198fc8bfce1b570e49da7cde010aa552e3))
|
||||
* Crab? (#586) ([fa9f522b](https://github.com/rust-lang/rustlings/commit/fa9f522b7f043d7ef73a39f003a9272dfe72c4f4))
|
||||
* add "rustlings list" command ([838f9f30](https://github.com/rust-lang/rustlings/commit/838f9f30083d0b23fd67503dcf0fbeca498e6647))
|
||||
* **try_from_into:** remove duplicate annotation ([04f1d079](https://github.com/rust-lang/rustlings/commit/04f1d079aa42a2f49af694bc92c67d731d31a53f))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* update structs README ([bcf14cf6](https://github.com/rust-lang/rustlings/commit/bcf14cf677adb3a38a3ac3ca53f3c69f61153025))
|
||||
* added missing exercises to info.toml ([90cfb6ff](https://github.com/rust-lang/rustlings/commit/90cfb6ff28377531bfc34acb70547bdb13374f6b))
|
||||
* gives a bit more context to magic number ([30644c9a](https://github.com/rust-lang/rustlings/commit/30644c9a062b825c0ea89435dc59f0cad86b110e))
|
||||
* **functions2:** Change signature to trigger precise error message: (#605) ([0ef95947](https://github.com/rust-lang/rustlings/commit/0ef95947cc30482e63a7045be6cc2fb6f6dcb4cc))
|
||||
* **structs1:** Adjust wording (#573) ([9334783d](https://github.com/rust-lang/rustlings/commit/9334783da31d821cc59174fbe8320df95828926c))
|
||||
* **try_from_into:**
|
||||
* type error ([4f4cfcf3](https://github.com/rust-lang/rustlings/commit/4f4cfcf3c36c8718c7c170c9c3a6935e6ef0618c))
|
||||
* Update description (#584) ([96347df9](https://github.com/rust-lang/rustlings/commit/96347df9df294f01153b29d9ad4ba361f665c755))
|
||||
* **vec1:** Have test compare every element in a and v ([9b6c6293](https://github.com/rust-lang/rustlings/commit/9b6c629397b24b944f484f5b2bbd8144266b5695))
|
||||
|
||||
<a name="4.2.0"></a>
|
||||
## 4.2.0 (2020-11-07)
|
||||
|
||||
#### Features
|
||||
|
||||
* Add HashMap exercises ([633c00cf](https://github.com/rust-lang/rustlings/commit/633c00cf8071e1e82959a3010452a32f34f29fc9))
|
||||
* Add Vec exercises ([0c12fa31](https://github.com/rust-lang/rustlings/commit/0c12fa31c57c03c6287458a0a8aca7afd057baf6))
|
||||
* **primitive_types6:** Add a test (#548) ([2b1fb2b7](https://github.com/rust-lang/rustlings/commit/2b1fb2b739bf9ad8d6b7b12af25fee173011bfc4))
|
||||
* **try_from_into:** Add tests (#571) ([95ccd926](https://github.com/rust-lang/rustlings/commit/95ccd92616ae79ba287cce221101e0bbe4f68cdc))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* log error output when inotify limit is exceeded ([d61b4e5a](https://github.com/rust-lang/rustlings/commit/d61b4e5a13b44d72d004082f523fa1b6b24c1aca))
|
||||
* more unique temp_file ([5643ef05](https://github.com/rust-lang/rustlings/commit/5643ef05bc81e4a840e9456f4406a769abbe1392))
|
||||
* **installation:** Update the MinRustVersion ([21bfb2d4](https://github.com/rust-lang/rustlings/commit/21bfb2d4777429c87d8d3b5fbf0ce66006dcd034))
|
||||
* **iterators2:** Update description (#578) ([197d3a3d](https://github.com/rust-lang/rustlings/commit/197d3a3d8961b2465579218a6749b2b2cefa8ddd))
|
||||
* **primitive_types6:**
|
||||
* remove 'unused doc comment' warning ([472d8592](https://github.com/rust-lang/rustlings/commit/472d8592d65c8275332a20dfc269e7ac0d41bc88))
|
||||
* missing comma in test ([4fb230da](https://github.com/rust-lang/rustlings/commit/4fb230daf1251444fcf29e085cee222a91f8a37e))
|
||||
* **quiz3:** Second test is for odd numbers, not even. (#553) ([18e0bfef](https://github.com/rust-lang/rustlings/commit/18e0bfef1de53071e353ba1ec5837002ff7290e6))
|
||||
|
||||
<a name="4.1.0"></a>
|
||||
## 4.1.0 (2020-10-05)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Update rustlings version in Cargo.lock ([1cc40bc9](https://github.com/rust-lang/rustlings/commit/1cc40bc9ce95c23d56f6d91fa1c4deb646231fef))
|
||||
* **arc1:** index mod should equal thread count ([b4062ef6](https://github.com/rust-lang/rustlings/commit/b4062ef6993e80dac107c4093ea85166ad3ee0fa))
|
||||
* **enums3:** Update Message::ChangeColor to take a tuple. (#457) ([4b6540c7](https://github.com/rust-lang/rustlings/commit/4b6540c71adabad647de8a09e57295e7c7c7d794))
|
||||
* **exercises:** adding question mark to quiz2 ([101072ab](https://github.com/rust-lang/rustlings/commit/101072ab9f8c80b40b8b88cb06cbe38aca2481c5))
|
||||
* **generics3:** clarify grade change ([47f7672c](https://github.com/rust-lang/rustlings/commit/47f7672c0307732056e7426e81d351f0dd7e22e5))
|
||||
* **structs3:** Small adjustment of variable name ([114b54cb](https://github.com/rust-lang/rustlings/commit/114b54cbdb977234b39e5f180d937c14c78bb8b2))
|
||||
* **using_as:** Add test so that proper type is returned. (#512) ([3286c5ec](https://github.com/rust-lang/rustlings/commit/3286c5ec19ea5fb7ded81d047da5f8594108a490))
|
||||
|
||||
#### Features
|
||||
|
||||
* Added iterators1.rs exercise ([9642f5a3](https://github.com/rust-lang/rustlings/commit/9642f5a3f686270a4f8f6ba969919ddbbc4f7fdd))
|
||||
* Add ability to run rustlings on repl.it (#471) ([8f7b5bd0](https://github.com/rust-lang/rustlings/commit/8f7b5bd00eb83542b959830ef55192d2d76db90a))
|
||||
* Add gitpod support (#473) ([4821a8be](https://github.com/rust-lang/rustlings/commit/4821a8be94af4f669042a06ab917934cfacd032f))
|
||||
* Remind the user of the hint option (#425) ([816b1f5e](https://github.com/rust-lang/rustlings/commit/816b1f5e85d6cc6e72673813a85d0ada2a8f84af))
|
||||
* Remind the user of the hint option (#425) ([9f61db5d](https://github.com/rust-lang/rustlings/commit/9f61db5dbe38538cf06571fcdd5f806e7901e83a))
|
||||
* **cli:** Added 'cls' command to 'watch' mode (#474) ([4f2468e1](https://github.com/rust-lang/rustlings/commit/4f2468e14f574a93a2e9b688367b5752ed96ae7b))
|
||||
* **try_from_into:** Add insufficient length test (#469) ([523d18b8](https://github.com/rust-lang/rustlings/commit/523d18b873a319f7c09262f44bd40e2fab1830e5))
|
||||
|
||||
<a name="4.0.0"></a>
|
||||
## 4.0.0 (2020-07-08)
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
* Add a --nocapture option to display test harnesses' outputs ([8ad5f9bf](https://github.com/rust-lang/rustlings/commit/8ad5f9bf531a4848b1104b7b389a20171624c82f))
|
||||
* Rename test to quiz, fixes #244 ([010a0456](https://github.com/rust-lang/rustlings/commit/010a04569282149cea7f7a76fc4d7f4c9f0f08dd))
|
||||
|
||||
#### Features
|
||||
|
||||
* Add traits README ([173bb141](https://github.com/rust-lang/rustlings/commit/173bb14140c5530cbdb59e53ace3991a99d804af))
|
||||
* Add box1.rs exercise ([7479a473](https://github.com/rust-lang/rustlings/commit/7479a4737bdcac347322ad0883ca528c8675e720))
|
||||
* Rewrite try_from_into (#393) ([763aa6e3](https://github.com/rust-lang/rustlings/commit/763aa6e378a586caae2d8d63755a85eeba227933))
|
||||
* Add if2 exercise ([1da84b5f](https://github.com/rust-lang/rustlings/commit/1da84b5f7c489f65bd683c244f13c7d1ee812df0))
|
||||
* Added exercise structs3.rs ([b66e2e09](https://github.com/rust-lang/rustlings/commit/b66e2e09622243e086a0f1258dd27e1a2d61c891))
|
||||
* Add exercise variables6 covering const (#352) ([5999acd2](https://github.com/rust-lang/rustlings/commit/5999acd24a4f203292be36e0fd18d385887ec481))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Change then to than ([ddd98ad7](https://github.com/rust-lang/rustlings/commit/ddd98ad75d3668fbb10eff74374148aa5ed2344d))
|
||||
* rename quiz1 to tests1 in info (#420) ([0dd1c6ca](https://github.com/rust-lang/rustlings/commit/0dd1c6ca6b389789e0972aa955fe17aa15c95f29))
|
||||
* fix quiz naming inconsistency (#421) ([5563adbb](https://github.com/rust-lang/rustlings/commit/5563adbb890587fc48fbbc9c4028642687f1e85b))
|
||||
* confine the user further in variable exercises ([06ef4cc6](https://github.com/rust-lang/rustlings/commit/06ef4cc654e75d22a526812919ee49b8956280bf))
|
||||
* update iterator and macro text for typos and clarity ([95900828](https://github.com/rust-lang/rustlings/commit/959008284834bece0196a01e17ac69a7e3590116))
|
||||
* update generics2 closes #362 ([964c974a](https://github.com/rust-lang/rustlings/commit/964c974a0274199d755073b917c2bc5da0c9b4f1))
|
||||
* confusing comment in conversions/try_from_into.rs ([c9e4f2cf](https://github.com/rust-lang/rustlings/commit/c9e4f2cfb4c48d0b7451263cfb43b9426438122d))
|
||||
* **arc1:** Passively introduce attributes (#429) ([113cdae2](https://github.com/rust-lang/rustlings/commit/113cdae2d4e4c55905e8056ad326ede7fd7de356))
|
||||
* **box1:** fix comment typo (#426) ([bb2ca251](https://github.com/rust-lang/rustlings/commit/bb2ca251106b27a7272d9a30872904dd1376654c))
|
||||
* **errorsn:** Try harder to confine the user. (#388) ([2b20c8a0](https://github.com/rust-lang/rustlings/commit/2b20c8a0f5774d07c58d110d75879f33fc6273b5))
|
||||
* **from_into.rs:** typo ([a901499e](https://github.com/rust-lang/rustlings/commit/a901499ededd3ce1995164700514fe4e9a0373ea))
|
||||
* **generics2:** Guide students to the answer (#430) ([e6bd8021](https://github.com/rust-lang/rustlings/commit/e6bd8021d9a7dd06feebc30c9d5f953901d7b419))
|
||||
* **installation:**
|
||||
* Provide a backup git reference when tag can't be curl ([9e4fb100](https://github.com/rust-lang/rustlings/commit/9e4fb1009f1c9e3433915c03e22c2af422e5c5fe))
|
||||
* Check if python is available while checking for git,rustc and cargo ([9cfb617d](https://github.com/rust-lang/rustlings/commit/9cfb617d5b0451b4b51644a1298965390cda9884))
|
||||
* **option1:**
|
||||
* Don't add only zeros to the numbers array ([cce6a442](https://github.com/rust-lang/rustlings/commit/cce6a4427718724a9096800754cd3abeca6a1580))
|
||||
* Add cast to usize, as it is confusing in the context of an exercise about Option ([f6cffc7e](https://github.com/rust-lang/rustlings/commit/f6cffc7e487b42f15a6f958e49704c93a8d4465b))
|
||||
* **option2:** Add TODO to comments (#400) ([10967bce](https://github.com/rust-lang/rustlings/commit/10967bce57682812dc0891a9f9757da1a9d87404))
|
||||
* **options1:** Add hint about Array Initialization (#389) ([9f75554f](https://github.com/rust-lang/rustlings/commit/9f75554f2a30295996f03f0160b98c0458305502))
|
||||
* **test2:** name of type String and &str (#394) ([d6c0a688](https://github.com/rust-lang/rustlings/commit/d6c0a688e6a96f93ad60d540d4b326f342fc0d45))
|
||||
* **variables6:** minor typo (#419) ([524e17df](https://github.com/rust-lang/rustlings/commit/524e17df10db95f7b90a0f75cc8997182a8a4094))
|
||||
|
||||
<a name="3.0.0"></a>
|
||||
## 3.0.0 (2020-04-11)
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
* make "compile" exercises print output (#278) ([3b6d5c](https://github.com/fmoko/rustlings/commit/3b6d5c3aaa27a242a832799eb66e96897d26fde3))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* **primitive_types:** revert primitive_types4 (#296) ([b3a3351e](https://github.com/rust-lang/rustlings/commit/b3a3351e8e6a0bdee07077d7b0382953821649ae))
|
||||
* **run:** compile clippy exercise files (#295) ([3ab084a4](https://github.com/rust-lang/rustlings/commit/3ab084a421c0f140ae83bf1fc3f47b39342e7373))
|
||||
* **conversions:**
|
||||
* add additional test to meet exercise rules (#284) ([bc22ec3](https://github.com/fmoko/rustlings/commit/bc22ec382f843347333ef1301fc1bad773657f38))
|
||||
* remove duplicate not done comment (#292) ([dab90f](https://github.com/fmoko/rustlings/commit/dab90f7b91a6000fe874e3d664f244048e5fa342))
|
||||
* don't hardcode documentation version for traits (#288) ([30e6af](https://github.com/fmoko/rustlings/commit/30e6af60690c326fb5d3a9b7335f35c69c09137d))
|
||||
|
||||
#### Features
|
||||
|
||||
* add Option2 exercise (#290) ([86b5c08b](https://github.com/rust-lang/rustlings/commit/86b5c08b9bea1576127a7c5f599f5752072c087d))
|
||||
* add excercise for option (#282) ([135e5d47](https://github.com/rust-lang/rustlings/commit/135e5d47a7c395aece6f6022117fb20c82f2d3d4))
|
||||
* add new exercises for generics (#280) ([76be5e4e](https://github.com/rust-lang/rustlings/commit/76be5e4e991160f5fd9093f03ee2ba260e8f7229))
|
||||
* **ci:** add buildkite config ([b049fa2c](https://github.com/rust-lang/rustlings/commit/b049fa2c84dba0f0c8906ac44e28fd45fba51a71))
|
||||
|
||||
<a name="2.2.1"></a>
|
||||
### 2.2.1 (2020-02-27)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Re-add cloning the repo to install scripts ([3d9b03c5](https://github.com/rust-lang/rustlings/commit/3d9b03c52b8dc51b140757f6fd25ad87b5782ef5))
|
||||
|
||||
#### Features
|
||||
|
||||
* Add clippy lints (#269) ([1e2fd9c9](https://github.com/rust-lang/rustlings/commit/1e2fd9c92f8cd6e389525ca1a999fca4c90b5921))
|
||||
|
||||
<a name="2.2.0"></a>
|
||||
## 2.2.0 (2020-02-25)
|
||||
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Update deps to version compatable with aarch64-pc-windows (#263) ([19a93428](https://github.com/rust-lang/rustlings/commit/19a93428b3c73d994292671f829bdc8e5b7b3401))
|
||||
* **docs:**
|
||||
* Added a necessary step to Windows installation process (#242) ([3906efcd](https://github.com/rust-lang/rustlings/commit/3906efcd52a004047b460ed548037093de3f523f))
|
||||
* Fixed mangled sentence from book; edited for clarity (#266) ([ade52ff](https://github.com/rust-lang/rustlings/commit/ade52ffb739987287ddd5705944c8777705faed9))
|
||||
* Updated iterators readme to account for iterators4 exercise (#273) ([bec8e3a](https://github.com/rust-lang/rustlings/commit/bec8e3a644cbd88db1c73ea5f1d8a364f4a34016))
|
||||
* **installation:** make fatal errors more obvious (#272) ([17d0951e](https://github.com/rust-lang/rustlings/commit/17d0951e66fda8e11b204d5c4c41a0d5e22e78f7))
|
||||
* **iterators2:**
|
||||
* Remove reference to missing iterators2.rs (#245) ([419f7797](https://github.com/rust-lang/rustlings/commit/419f7797f294e4ce6a2b883199731b5bde77d262))
|
||||
* **as_ref_mut:** Enable a test and improve per clippy's suggestion (#256) ([dfdf809](https://github.com/rust-lang/rustlings/commit/dfdf8093ebbd4145864995627b812780de52f902))
|
||||
* **tests1:**
|
||||
* Change test command ([fe10e06c](https://github.com/rust-lang/rustlings/commit/fe10e06c3733ddb4a21e90d09bf79bfe618e97ce)
|
||||
* Correct test command in tests1.rs comment (#263) ([39fa7ae](https://github.com/rust-lang/rustlings/commit/39fa7ae8b70ad468da49b06f11b2383135a63bcf))
|
||||
|
||||
#### Features
|
||||
|
||||
* Add variables5.rs exercise (#264) ([0c73609e](https://github.com/rust-lang/rustlings/commit/0c73609e6f2311295e95d6f96f8c747cfc4cba03))
|
||||
* Show a completion message when watching (#253) ([d25ee55a](https://github.com/rust-lang/rustlings/commit/d25ee55a3205882d35782e370af855051b39c58c))
|
||||
* Add type conversion and parsing exercises (#249) ([0c85dc11](https://github.com/rust-lang/rustlings/commit/0c85dc1193978b5165491b99cc4922caf8d14a65))
|
||||
* Created consistent money unit (#258) ([fd57f8f](https://github.com/rust-lang/rustlings/commit/fd57f8f2c1da2af8ddbebbccec214e6f40f4dbab))
|
||||
* Enable test for exercise test4 (#276) ([8b971ff](https://github.com/rust-lang/rustlings/commit/8b971ffab6079a706ac925f5917f987932b55c07))
|
||||
* Added traits exercises (#274 but specifically #216, which originally added
|
||||
this :heart:) ([b559cdd](https://github.com/rust-lang/rustlings/commit/b559cdd73f32c0d0cfc1feda39f82b3e3583df17))
|
||||
|
||||
|
||||
<a name="2.1.0"></a>
|
||||
## 2.1.0 (2019-11-27)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* add line numbers in several exercises and hints ([b565c4d3](https://github.com/rust-lang/rustlings/commit/b565c4d3e74e8e110bef201a082fa1302722a7c3))
|
||||
* **arc1:** Fix some words in the comment ([c42c3b21](https://github.com/rust-lang/rustlings/commit/c42c3b2101df9164c8cd7bb344def921e5ba3e61))
|
||||
* **enums:** Add link to chapter on pattern syntax (#242) ([615ce327](https://github.com/rust-lang/rustlings/commit/615ce3279800c56d89f19d218ccb7ef576624feb))
|
||||
* **primitive_types4:**
|
||||
* update outdated hint ([4c5189df](https://github.com/rust-lang/rustlings/commit/4c5189df2bdd9a231f6b2611919ba5aa14da0d3f))
|
||||
* update outdated comment ([ded2c034](https://github.com/rust-lang/rustlings/commit/ded2c034ba93fa1e3c2c2ea16b83abc1a57265e8))
|
||||
* **strings2:** update line number in hint ([a09f684f](https://github.com/rust-lang/rustlings/commit/a09f684f05c58d239a6fc59ec5f81c2533e8b820))
|
||||
* **variables1:** Correct wrong word in comment ([fda5a470](https://github.com/rust-lang/rustlings/commit/fda5a47069e0954f16a04e8e50945e03becb71a5))
|
||||
|
||||
#### Features
|
||||
|
||||
* **watch:** show hint while watching ([8143d57b](https://github.com/rust-lang/rustlings/commit/8143d57b4e88c51341dd4a18a14c536042cc009c))
|
||||
|
||||
<a name="2.0.0"></a>
|
||||
## 2.0.0 (2019-11-12)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* **default:** Clarify the installation procedure ([c371b853](https://github.com/rust-lang/rustlings/commit/c371b853afa08947ddeebec0edd074b171eeaae0))
|
||||
* **info:** Fix trailing newlines for hints ([795b6e34](https://github.com/rust-lang/rustlings/commit/795b6e348094a898e9227a14f6232f7bb94c8d31))
|
||||
* **run:** make `run` never prompt ([4b265465](https://github.com/rust-lang/rustlings/commit/4b26546589f7d2b50455429482cf1f386ceae8b3))
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
* Refactor hint system ([9bdb0a12](https://github.com/rust-lang/rustlings/commit/9bdb0a12e45a8e9f9f6a4bd4a9c172c5376c7f60))
|
||||
* improve `watch` execution mode ([2cdd6129](https://github.com/rust-lang/rustlings/commit/2cdd61294f0d9a53775ee24ad76435bec8a21e60))
|
||||
* Index exercises by name ([627cdc07](https://github.com/rust-lang/rustlings/commit/627cdc07d07dfe6a740e885e0ddf6900e7ec336b))
|
||||
* **run:** makes `run` never prompt ([4b265465](https://github.com/rust-lang/rustlings/commit/4b26546589f7d2b50455429482cf1f386ceae8b3))
|
||||
|
||||
#### Features
|
||||
|
||||
* **cli:** check for rustc before doing anything ([36a033b8](https://github.com/rust-lang/rustlings/commit/36a033b87a6549c1e5639c908bf7381c84f4f425))
|
||||
* **hint:** Add test for hint ([ce9fa6eb](https://github.com/rust-lang/rustlings/commit/ce9fa6ebbfdc3e7585d488d9409797285708316f))
|
||||
|
||||
<a name="1.5.1"></a>
|
||||
### 1.5.1 (2019-11-11)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* **errors3:** Update hint ([dcfb427b](https://github.com/rust-lang/rustlings/commit/dcfb427b09585f0193f0a294443fdf99f11c64cb), closes [#185](https://github.com/rust-lang/rustlings/issues/185))
|
||||
* **if1:** Remove `return` reference ([ad03d180](https://github.com/rust-lang/rustlings/commit/ad03d180c9311c0093e56a3531eec1a9a70cdb45))
|
||||
* **strings:** Move Strings before Structs ([6dcecb38](https://github.com/rust-lang/rustlings/commit/6dcecb38a4435593beb87c8e12d6314143631482), closes [#204](https://github.com/rust-lang/rustlings/issues/204))
|
||||
* **structs1:** Remove misleading comment ([f72e5a8f](https://github.com/rust-lang/rustlings/commit/f72e5a8f05568dde04eaeac10b9a69872f21cb37))
|
||||
* **threads:** Move Threads behind SLT ([fbe91a67](https://github.com/rust-lang/rustlings/commit/fbe91a67a482bfe64cbcdd58d06ba830a0f39da3), closes [#205](https://github.com/rust-lang/rustlings/issues/205))
|
||||
* **watch:** clear screen before each `verify()` ([3aff590](https://github.com/rust-lang/rustlings/commit/3aff59085586c24196a547c2693adbdcf4432648))
|
||||
|
||||
<a name="1.5.0"></a>
|
||||
## 1.5.0 (2019-11-09)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* **test1:** Rewrite logic ([79a56942](https://github.com/rust-lang/rustlings/commit/79a569422c8309cfc9e4aed25bf4ab3b3859996b))
|
||||
* **installation:** Fix rustlings installation check ([7a252c47](https://github.com/rust-lang/rustlings/commit/7a252c475551486efb52f949b8af55803b700bc6))
|
||||
* **iterators:** Rename iterator3.rs ([433d2115](https://github.com/rust-lang/rustlings/commit/433d2115bc1c04b6d34a335a18c9a8f3e2672bc6))
|
||||
* **iterators2:** Remove syntax resulting in misleading error message ([4cde8664](https://github.com/rust-lang/rustlings/commit/4cde86643e12db162a66e62f23b78962986046ac))
|
||||
* **option1:**
|
||||
* Fix arguments passed to assert! macro (#222) ([4c2cf6da](https://github.com/rust-lang/rustlings/commit/4c2cf6da755efe02725e05ecc3a303304c10a6da))
|
||||
* Fix arguments passed to assert! macro ([ead4f7af](https://github.com/rust-lang/rustlings/commit/ead4f7af9e10e53418efdde5c359159347282afd))
|
||||
* Add test for prematurely passing exercise ([a750e4a1](https://github.com/rust-lang/rustlings/commit/a750e4a1a3006227292bb17d57d78ce84da6bfc6))
|
||||
* **primitive_types4:** Fail on a slice covering the wrong area ([5b1e673c](https://github.com/rust-lang/rustlings/commit/5b1e673cec1658afc4ebbbc800213847804facf5))
|
||||
* **readme:** http to https ([70946b85](https://github.com/rust-lang/rustlings/commit/70946b85e536e80e70ed9505cb650ca0a3a1fbb5))
|
||||
* **test1:**
|
||||
* Swap assertion parameter order ([4086d463](https://github.com/rust-lang/rustlings/commit/4086d463a981e81d97781851d17db2ced290f446))
|
||||
* renamed function name to snake case closes #180 ([89d5186c](https://github.com/rust-lang/rustlings/commit/89d5186c0dae8135ecabf90ee8bb35949bc2d29b))
|
||||
|
||||
#### Features
|
||||
|
||||
* Add enums exercises ([dc150321](https://github.com/rust-lang/rustlings/commit/dc15032112fc485226a573a18139e5ce928b1755))
|
||||
* Added exercise for struct update syntax ([1c4c8764](https://github.com/rust-lang/rustlings/commit/1c4c8764ed118740cd4cee73272ddc6cceb9d959))
|
||||
* **iterators2:** adds iterators2 exercise including config ([9288fccf](https://github.com/rust-lang/rustlings/commit/9288fccf07a2c5043b76d0fd6491e4cf72d76031))
|
||||
|
||||
<a name="1.4.1"></a>
|
||||
### 1.4.1 (2019-08-13)
|
||||
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* **iterators2:** Remove syntax resulting in misleading error message ([4cde8664](https://github.com/rust-lang/rustlings/commit/4cde86643e12db162a66e62f23b78962986046ac))
|
||||
* **option1:** Add test for prematurely passing exercise ([a750e4a1](https://github.com/rust-lang/rustlings/commit/a750e4a1a3006227292bb17d57d78ce84da6bfc6))
|
||||
* **test1:** Swap assertion parameter order ([4086d463](https://github.com/rust-lang/rustlings/commit/4086d463a981e81d97781851d17db2ced290f446))
|
||||
|
||||
|
||||
|
||||
<a name="1.4.0"></a>
|
||||
## 1.4.0 (2019-07-13)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* **installation:** Fix rustlings installation check ([7a252c47](https://github.com/rust-lang/rustlings/commit/7a252c475551486efb52f949b8af55803b700bc6))
|
||||
* **iterators:** Rename iterator3.rs ([433d2115](https://github.com/rust-lang/rustlings/commit/433d2115bc1c04b6d34a335a18c9a8f3e2672bc6))
|
||||
* **readme:** http to https ([70946b85](https://github.com/rust-lang/rustlings/commit/70946b85e536e80e70ed9505cb650ca0a3a1fbb5))
|
||||
* **test1:** renamed function name to snake case ([89d5186c](https://github.com/rust-lang/rustlings/commit/89d5186c0dae8135ecabf90ee8bb35949bc2d29b))
|
||||
* **cli:** Check if changed exercise file exists before calling verify ([ba85ca3](https://github.com/rust-lang/rustlings/commit/ba85ca32c4cfc61de46851ab89f9c58a28f33c88))
|
||||
* **structs1:** Fix the irrefutable let pattern warning ([cc6a141](https://github.com/rust-lang/rustlings/commit/cc6a14104d7c034eadc98297eaaa972d09c50b1f))
|
||||
|
||||
#### Features
|
||||
|
||||
* **changelog:** Use clog for changelogs ([34e31232](https://github.com/rust-lang/rustlings/commit/34e31232dfddde284a341c9609b33cd27d9d5724))
|
||||
* **iterators2:** adds iterators2 exercise including config ([9288fccf](https://github.com/rust-lang/rustlings/commit/9288fccf07a2c5043b76d0fd6491e4cf72d76031))
|
||||
|
||||
<a name="1.3.0"></a>
|
||||
### 1.3.0 (2019-06-05)
|
||||
|
||||
#### Features
|
||||
|
||||
- Adds a simple exercise for structures (#163, @briankung)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
- Add Result type signature as it is difficult for new comers to understand Generics and Error all at once. (#157, @veggiemonk)
|
||||
- Rustfmt and whitespace fixes (#161, @eddyp)
|
||||
- errorsn.rs: Separate also the hints from each other to avoid accidental viewing (#162, @eddyp)
|
||||
- fixed outdated links (#165, @gushroom)
|
||||
- Fix broken link (#164, @HanKruiger)
|
||||
- Remove highlighting and syntect (#167, @komaeda)
|
||||
|
||||
<a name="1.2.2"></a>
|
||||
### 1.2.2 (2019-05-07)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
- Reverted `--nocapture` flag since it was causing tests to pass unconditionally
|
||||
|
||||
<a name="1.2.1"></a>
|
||||
### 1.2.1 (2019-04-22)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
- Fix the `--nocapture` feature (@komaeda)
|
||||
- Provide a nicer error message for when you're in the wrong directory
|
||||
|
||||
<a name="1.2.0"></a>
|
||||
### 1.2.0 (2019-04-22)
|
||||
|
||||
#### Features
|
||||
|
||||
- Add errors to exercises that compile without user changes (@yvan-sraka)
|
||||
- Use --nocapture when testing, enabling `println!` when running (@komaeda)
|
||||
|
||||
<a name="1.1.1"></a>
|
||||
### 1.1.1 (2019-04-14)
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
- Fix permissions on exercise files (@zacanger, #133)
|
||||
- Make installation checks more thorough (@komaeda, 1b3469f236bc6979c27f6e1a04e4138a88e55de3)
|
||||
- Fix order of true/false in tests for executables (@mgeier, #137)
|
||||
- Stop run from panicking when compile fails (@cjpearce, #141)
|
||||
- Fix intermittent test failure caused by race condition (@cjpearce, #140)
|
||||
- Fix links by deleting book version (@diodfr, #142)
|
||||
- Canonicalize paths to fix path matching (@cjpearce, #143)
|
||||
|
||||
<a name="1.1.0"></a>
|
||||
### 1.1.0 (2019-03-20)
|
||||
|
||||
- errors2.rs: update link to Rust book (#124)
|
||||
- Start verification at most recently modified file (#120)
|
||||
- Watch for file creation events in watch mode (#117)
|
||||
- Add standard library types to exercises suite (#119)
|
||||
- Give a warning when Rustlings isn't run from the right directory (#123)
|
||||
- Verify that rust version is recent enough to install Rustlings (#131)
|
||||
|
||||
<a name="1.0.1"></a>
|
||||
### 1.0.1 (2019-03-06)
|
||||
|
||||
- Adds a way to install Rustlings in one command (`curl -L https://git.io/rustlings | bash`)
|
||||
- Makes `rustlings watch` react to create file events (@shaunbennett, #117)
|
||||
- Reworks the exercise management to use an external TOML file instead of just listing them in the code
|
||||
|
||||
<a name="1.0.0"></a>
|
||||
### 1.0.0 (2019-03-06)
|
||||
|
||||
Initial release.
|
131
CONTRIBUTING.md
131
CONTRIBUTING.md
|
@ -1,131 +0,0 @@
|
|||
## Contributing to Rustlings
|
||||
|
||||
First off, thanks for taking the time to contribute!! ❤️
|
||||
|
||||
### Quick Reference
|
||||
|
||||
I want to...
|
||||
|
||||
_add an exercise! ➡️ [read this](#addex) and then [open a Pull Request](#prs)_
|
||||
|
||||
_update an outdated exercise! ➡️ [open a Pull Request](#prs)_
|
||||
|
||||
_report a bug! ➡️ [open an Issue](#issues)_
|
||||
|
||||
_fix a bug! ➡️ [open a Pull Request](#prs)_
|
||||
|
||||
_implement a new feature! ➡️ [open an Issue to discuss it first, then a Pull Request](#issues)_
|
||||
|
||||
<a name="#src"></a>
|
||||
### Working on the source code
|
||||
|
||||
`rustlings` is basically a glorified `rustc` wrapper. Therefore the source code
|
||||
isn't really that complicated since the bulk of the work is done by `rustc`.
|
||||
`src/main.rs` contains a simple `clap` CLI that loads from `src/verify.rs` and `src/run.rs`.
|
||||
|
||||
<a name="addex"></a>
|
||||
### Adding an exercise
|
||||
|
||||
The first step is to add the exercise! Name the file `exercises/yourTopic/yourTopicN.rs`, make sure to
|
||||
put in some helpful links, and link to sections of the book in `exercises/yourTopic/README.md`.
|
||||
|
||||
Next make sure it runs with `rustlings`. The exercise metadata is stored in `info.toml`, under the `exercises` array. The order of the `exercises` array determines the order the exercises are run by `rustlings verify`.
|
||||
|
||||
Add the metadata for your exercise in the correct order in the `exercises` array. If you are unsure of the correct ordering, add it at the bottom and ask in your pull request. The exercise metadata should contain the following:
|
||||
```diff
|
||||
...
|
||||
+ [[exercises]]
|
||||
+ name = "yourTopicN"
|
||||
+ path = "exercises/yourTopic/yourTopicN.rs"
|
||||
+ mode = "compile"
|
||||
+ hint = """
|
||||
+ Some kind of useful hint for your exercise."""
|
||||
...
|
||||
```
|
||||
|
||||
The `mode` attribute decides whether Rustlings will only compile your exercise, or compile and test it. If you have tests to verify in your exercise, choose `test`, otherwise `compile`.
|
||||
|
||||
That's all! Feel free to put up a pull request.
|
||||
|
||||
<a name="issues"></a>
|
||||
### Issues
|
||||
|
||||
You can open an issue [here](https://github.com/rust-lang/rustlings/issues/new).
|
||||
If you're reporting a bug, please include the output of the following commands:
|
||||
|
||||
- `rustc --version`
|
||||
- `rustlings --version`
|
||||
- `ls -la`
|
||||
- Your OS name and version
|
||||
|
||||
<a name="prs"></a>
|
||||
### Pull Requests
|
||||
|
||||
Opening a pull request is as easy as forking the repository and committing your
|
||||
changes. There's a couple of things to watch out for:
|
||||
|
||||
#### Write correct commit messages
|
||||
|
||||
We follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.4/)
|
||||
specification, because it makes it easier to generate changelogs automatically.
|
||||
This means that you have to format your commit messages in a specific way. Say
|
||||
you're working on adding a new exercise called `foobar1.rs`. You could write
|
||||
the following commit message:
|
||||
|
||||
```
|
||||
feat: Add foobar1.rs exercise
|
||||
```
|
||||
|
||||
If you're just fixing a bug, please use the `fix` type:
|
||||
|
||||
```
|
||||
fix(verify): Make sure verify doesn't self-destruct
|
||||
```
|
||||
|
||||
The scope within the brackets is optional, but should be any of these:
|
||||
|
||||
- `installation` (for the installation script)
|
||||
- `cli` (for general CLI changes)
|
||||
- `verify` (for the verification source file)
|
||||
- `watch` (for the watch functionality source)
|
||||
- `run` (for the run functionality source)
|
||||
- `EXERCISENAME` (if you're changing a specific exercise, or set of exercises,
|
||||
substitute them here)
|
||||
|
||||
When the commit also happens to close an existing issue, link it in the message
|
||||
body:
|
||||
|
||||
```
|
||||
fix: Update foobar
|
||||
|
||||
closes #101029908
|
||||
```
|
||||
|
||||
If you're doing simple changes, like updating a book link, use `chore`:
|
||||
|
||||
```
|
||||
chore: Update exercise1.rs book link
|
||||
```
|
||||
|
||||
If you're updating documentation, use `docs`:
|
||||
|
||||
```
|
||||
docs: Add more information to Readme
|
||||
```
|
||||
|
||||
If, and only if, you're absolutely sure you want to make a breaking change
|
||||
(please discuss this beforehand!), add an exclamation mark to the type and
|
||||
explain the breaking change in the message body:
|
||||
|
||||
```
|
||||
fix!: Completely change verification
|
||||
|
||||
BREAKING CHANGE: This has to be done because lorem ipsum dolor
|
||||
```
|
||||
|
||||
#### Pull Request Workflow
|
||||
|
||||
Once you open a Pull Request, it may be reviewed or labeled (or both) until
|
||||
the maintainers accept your change. Then, [bors](https://github.com/bors) will
|
||||
run the test suite with your changes and if it's successful, automatically
|
||||
merge it in!
|
747
Cargo.lock
generated
747
Cargo.lock
generated
|
@ -1,747 +0,0 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argh"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e7317a549bc17c5278d9e72bb6e62c6aa801ac2567048e39ebc1c194249323e"
|
||||
dependencies = [
|
||||
"argh_derive",
|
||||
"argh_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argh_derive"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60949c42375351e9442e354434b0cba2ac402c1237edf673cac3a4bf983b8d3c"
|
||||
dependencies = [
|
||||
"argh_shared",
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argh_shared"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a61eb019cb8f415d162cb9f12130ee6bbe9168b7d953c17f4ad049e4051ca00"
|
||||
|
||||
[[package]]
|
||||
name = "assert_cmd"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dc477793bd82ec39799b6f6b3df64938532fdf2ab0d49ef817eac65856a5a1e"
|
||||
dependencies = [
|
||||
"escargot",
|
||||
"predicates",
|
||||
"predicates-core",
|
||||
"predicates-tree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clicolors-control"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ca57c2c14b8a2bf3105bc9d15574aad80babf6a9c44b1058034cdf8bd169628"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"clicolors-control",
|
||||
"encode_unicode",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"parking_lot",
|
||||
"regex",
|
||||
"termios",
|
||||
"unicode-width",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"regex",
|
||||
"terminal_size",
|
||||
"unicode-width",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "difference"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
|
||||
[[package]]
|
||||
name = "escargot"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ceb9adbf9874d5d028b5e4c5739d22b71988252b25c9c98fe7cf9738bee84597"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "float-cmp"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fsevent-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fuchsia-zircon-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indicatif"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ecd1e2ee08e6c255ce890f5a99d17000850e664e7acf119fb03b25b0575bfe"
|
||||
dependencies = [
|
||||
"console 0.14.1",
|
||||
"lazy_static",
|
||||
"number_prefix",
|
||||
"parking_lot",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"inotify-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"fuchsia-zircon",
|
||||
"fuchsia-zircon-sys",
|
||||
"iovec",
|
||||
"kernel32-sys",
|
||||
"libc",
|
||||
"log",
|
||||
"miow",
|
||||
"net2",
|
||||
"slab",
|
||||
"winapi 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-extras"
|
||||
version = "2.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
|
||||
dependencies = [
|
||||
"lazycell",
|
||||
"log",
|
||||
"mio",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
|
||||
dependencies = [
|
||||
"kernel32-sys",
|
||||
"net2",
|
||||
"winapi 0.2.8",
|
||||
"ws2_32-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "normalize-line-endings"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "4.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"filetime",
|
||||
"fsevent",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
"libc",
|
||||
"mio",
|
||||
"mio-extras",
|
||||
"walkdir",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "number_prefix"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "predicates"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f49cfaf7fdaa3bfacc6fa3e7054e65148878354a5cfddcf661df4c851f8021df"
|
||||
dependencies = [
|
||||
"difference",
|
||||
"float-cmp",
|
||||
"normalize-line-endings",
|
||||
"predicates-core",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "predicates-core"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451"
|
||||
|
||||
[[package]]
|
||||
name = "predicates-tree"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7dd0fd014130206c9352efbdc92be592751b2b9274dff685348341082c6ea3d"
|
||||
dependencies = [
|
||||
"predicates-core",
|
||||
"treeline",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "rustlings"
|
||||
version = "4.6.0"
|
||||
dependencies = [
|
||||
"argh",
|
||||
"assert_cmd",
|
||||
"console 0.7.7",
|
||||
"glob",
|
||||
"indicatif",
|
||||
"notify",
|
||||
"predicates",
|
||||
"regex",
|
||||
"serde",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.129"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1f72836d2aa753853178eda473a3b9d8e4eefdaf20523b919677e6de489f8f1"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.129"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e57ae87ad533d9a56427558b516d0adac283614e347abf85b0dc0cbbf0a249f3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termios"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "treeline"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi 0.3.9",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
24
Cargo.toml
24
Cargo.toml
|
@ -1,23 +1,9 @@
|
|||
[package]
|
||||
name = "rustlings"
|
||||
version = "4.6.0"
|
||||
authors = ["anastasie <ana@ana.st>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
|
||||
edition = "2021"
|
||||
version = "0.1.0"
|
||||
authors = ["Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
argh = "0.1.4"
|
||||
indicatif = "0.10.3"
|
||||
console = "0.7.7"
|
||||
notify = "4.0.15"
|
||||
toml = "0.4.10"
|
||||
regex = "1.1.6"
|
||||
serde = {version = "1.0.10", features = ["derive"]}
|
||||
|
||||
[[bin]]
|
||||
name = "rustlings"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "0.11.0"
|
||||
predicates = "1.0.1"
|
||||
glob = "0.3.0"
|
||||
handlebars = "0.32.0"
|
||||
serde_json = "1.0.10"
|
||||
prlink = { git = "https://github.com/btbytes/prlink" }
|
||||
|
|
191
README-template.hbs
Normal file
191
README-template.hbs
Normal file
|
@ -0,0 +1,191 @@
|
|||
<!--
|
||||
{{ autogenerated_notice }}
|
||||
-->
|
||||
|
||||
# rustlings
|
||||
|
||||
Small exercises to get you used to reading and writing Rust code. Includes practice reading and
|
||||
responding to compiler messages!
|
||||
|
||||
This repo is very much the smallest thing that could possibly work :)
|
||||
|
||||
## To do these exercises
|
||||
|
||||
Thanks to [btbytes'](https://twitter.com/btbytes) [prlinks](https://github.com/btbytes/prlink), you
|
||||
can now click on the links below to load the exercises in the rust playground!
|
||||
|
||||
There are infinite correct answers-- the exercises are sometimes left very open-ended. Scroll down
|
||||
in the playground to find comments that have hints.
|
||||
|
||||
If you need more help or would like to compare solutions, you can ask in [#rust-beginners on
|
||||
irc.mozilla.org](https://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-beginners ), the
|
||||
[user forum](https://users.rust-lang.org/), or [the subreddit](https://reddit.com/r/rust). If an
|
||||
exercise could be improved in any way, please [create an
|
||||
issue](https://github.com/carols10cents/rustlings/issues/new) or submit a pull request!
|
||||
|
||||
### Variable bindings
|
||||
|
||||
[Relevant chapter in The Rust Programming
|
||||
Language](https://doc.rust-lang.org/book/second-edition/ch03-01-variables-and-mutability.html)
|
||||
|
||||
{{ playground_link "variables/variables1.rs" }}
|
||||
{{ playground_link "variables/variables2.rs" }}
|
||||
{{ playground_link "variables/variables3.rs" }}
|
||||
{{ playground_link "variables/variables4.rs" }}
|
||||
|
||||
### Functions
|
||||
|
||||
[Relevant chapter in The Rust Programming
|
||||
Language](https://doc.rust-lang.org/book/second-edition/ch03-03-how-functions-work.html)
|
||||
|
||||
{{ playground_link "functions/functions1.rs" }}
|
||||
{{ playground_link "functions/functions2.rs" }}
|
||||
{{ playground_link "functions/functions3.rs" }}
|
||||
{{ playground_link "functions/functions4.rs" }}
|
||||
{{ playground_link "functions/functions5.rs" }}
|
||||
|
||||
### Primitive types
|
||||
|
||||
[Relevant chapter in The Rust Programming
|
||||
Language](https://doc.rust-lang.org/book/second-edition/ch03-02-data-types.html)
|
||||
|
||||
{{ playground_link "primitive_types/primitive_types1.rs" }}
|
||||
{{ playground_link "primitive_types/primitive_types2.rs" }}
|
||||
{{ playground_link "primitive_types/primitive_types3.rs" }}
|
||||
{{ playground_link "primitive_types/primitive_types4.rs" }}
|
||||
{{ playground_link "primitive_types/primitive_types5.rs" }}
|
||||
{{ playground_link "primitive_types/primitive_types6.rs" }}
|
||||
|
||||
### Tests
|
||||
|
||||
Going out of order from the book to cover tests-- many of the following exercises will ask you to
|
||||
make tests pass!
|
||||
|
||||
[Relevant chapter in The Rust Programming
|
||||
Language](https://doc.rust-lang.org/book/second-edition/ch11-01-writing-tests.html)
|
||||
|
||||
{{ playground_link "tests/tests1.rs" }}
|
||||
{{ playground_link "tests/tests2.rs" }}
|
||||
{{ playground_link "tests/tests3.rs" }}
|
||||
{{ playground_link "tests/tests4.rs" }}
|
||||
|
||||
### If
|
||||
|
||||
[Relevant chapter in The Rust Programming
|
||||
Language](https://doc.rust-lang.org/book/second-edition/ch03-05-control-flow.html)
|
||||
|
||||
{{ playground_link "if/if1.rs" }}
|
||||
|
||||
### Strings
|
||||
|
||||
[Relevant chapter in The Rust Programming
|
||||
Language](https://doc.rust-lang.org/book/second-edition/ch08-02-strings.html)
|
||||
|
||||
{{ playground_link "strings/strings1.rs" }}
|
||||
{{ playground_link "strings/strings2.rs" }}
|
||||
{{ playground_link "strings/strings3.rs" }}
|
||||
|
||||
### Move semantics
|
||||
|
||||
These exercises are adapted from [pnkfelix]()'s [Rust
|
||||
Tutorial](https://pnkfelix.github.io/rust-examples-icfp2014/) -- thank you Felix!!!
|
||||
|
||||
Relevant chapters in the book:
|
||||
|
||||
- [Ownership](https://doc.rust-lang.org/book/second-edition/ch04-01-what-is-ownership.html)
|
||||
- [References and borrowing](https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html)
|
||||
|
||||
Note that the exercises in this section may look similar to each other but they are subtly
|
||||
different :)
|
||||
|
||||
{{ playground_link "move_semantics/move_semantics1.rs" }}
|
||||
{{ playground_link "move_semantics/move_semantics2.rs" }}
|
||||
{{ playground_link "move_semantics/move_semantics3.rs" }}
|
||||
{{ playground_link "move_semantics/move_semantics4.rs" }}
|
||||
|
||||
### Modules
|
||||
|
||||
[Relevant chapter in The Rust Programming
|
||||
Language](https://doc.rust-lang.org/book/second-edition/ch07-01-mod-and-the-filesystem.html)
|
||||
|
||||
{{ playground_link "modules/modules1.rs" }}
|
||||
{{ playground_link "modules/modules2.rs" }}
|
||||
|
||||
### Macros
|
||||
|
||||
Check out:
|
||||
|
||||
- [The Macros section of the first edition of the book
|
||||
book](https://doc.rust-lang.org/book/first-edition/macros.html)
|
||||
- [The Macros appendix of the second edition of the
|
||||
book](https://doc.rust-lang.org/book/second-edition/appendix-04-macros.html)
|
||||
- [The Little Book of Rust Macros](https://danielkeep.github.io/tlborm/book/index.html)
|
||||
|
||||
{{ playground_link "macros/macros1.rs" }}
|
||||
{{ playground_link "macros/macros2.rs" }}
|
||||
{{ playground_link "macros/macros3.rs" }}
|
||||
{{ playground_link "macros/macros4.rs" }}
|
||||
|
||||
### Error Handling
|
||||
|
||||
The [Error
|
||||
Handling](https://doc.rust-lang.org/book/second-edition/ch09-02-recoverable-errors-with-result.html)
|
||||
and [Generics](https://doc.rust-lang.org/book/second-edition/ch10-01-syntax.html) sections are
|
||||
relevant.
|
||||
|
||||
{{ playground_link "error_handling/option1.rs" }}
|
||||
{{ playground_link "error_handling/result1.rs" }}
|
||||
{{ playground_link "error_handling/errors1.rs" }}
|
||||
{{ playground_link "error_handling/errors2.rs" }}
|
||||
{{ playground_link "error_handling/errors3.rs" }}
|
||||
{{ playground_link "error_handling/errorsn.rs" }}
|
||||
|
||||
### Standard library types
|
||||
|
||||
#### `Arc`
|
||||
|
||||
The [Concurrency](https://doc.rust-lang.org/book/second-edition/ch16-03-shared-state.html) section
|
||||
is relevant.
|
||||
|
||||
{{ playground_link "standard_library_types/arc1.rs" }}
|
||||
|
||||
#### Iterators
|
||||
|
||||
Do not adjust your monitors-- iterators 1 and 2 are indeed missing. Iterator 3 is a bit challenging
|
||||
so we're leaving space for some exercises to lead up to it!
|
||||
|
||||
Check out the [Iterators chapter of the
|
||||
book](https://doc.rust-lang.org/book/second-edition/ch13-02-iterators.html) and the [Iterator
|
||||
docs](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html).
|
||||
|
||||
{{ playground_link "standard_library_types/iterator3.rs" }}
|
||||
{{ playground_link "standard_library_types/iterators4.rs" }}
|
||||
|
||||
### Threads
|
||||
|
||||
See [the Dining Philosophers
|
||||
example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html) and the
|
||||
[Concurrency Chapter](https://doc.rust-lang.org/book/second-edition/ch16-01-threads.html) from the
|
||||
book.
|
||||
|
||||
{{ playground_link "threads/threads1.rs" }}
|
||||
|
||||
### Uncategorized
|
||||
|
||||
A few exercises based on things I've encountered or had trouble with getting used to.
|
||||
|
||||
{{ playground_link "ex1.rs" }}
|
||||
{{ playground_link "ex2.rs" }}
|
||||
{{ playground_link "ex3.rs" }}
|
||||
{{ playground_link "ex4.rs" }}
|
||||
{{ playground_link "ex5.rs" }}
|
||||
{{ playground_link "ex6.rs" }}
|
||||
|
||||
## To help with this repo/TODO list
|
||||
|
||||
* File issues for problems or suggestions!
|
||||
* Contribute more exercises! Anything that took you time to get used to, or that you had trouble
|
||||
with, or that deserves practice would be a good exercise!
|
||||
* How could the process of doing these exercises work better? This is an open-ended question :) Are
|
||||
the playground links good enough? Are there ways that we could make going to the next exercise
|
||||
easier without forking the playground??
|
432
README.md
432
README.md
File diff suppressed because one or more lines are too long
|
@ -1,25 +0,0 @@
|
|||
Thanks for installing Rustlings!
|
||||
|
||||
Is this your first time? Don't worry, Rustlings was made for beginners! We are
|
||||
going to teach you a lot of things about Rust, but before we can get
|
||||
started, here's a couple of notes about how Rustlings operates:
|
||||
|
||||
1. The central concept behind Rustlings is that you solve exercises. These
|
||||
exercises usually have some sort of syntax error in them, which will cause
|
||||
them to fail compilation or testing. Sometimes there's a logic error instead
|
||||
of a syntax error. No matter what error, it's your job to find it and fix it!
|
||||
You'll know when you fixed it because then, the exercise will compile and
|
||||
Rustlings will be able to move on to the next exercise.
|
||||
2. If you run Rustlings in watch mode (which we recommend), it'll automatically
|
||||
start with the first exercise. Don't get confused by an error message popping
|
||||
up as soon as you run Rustlings! This is part of the exercise that you're
|
||||
supposed to solve, so open the exercise file in an editor and start your
|
||||
detective work!
|
||||
3. If you're stuck on an exercise, there is a helpful hint you can view by typing
|
||||
'hint' (in watch mode), or running `rustlings hint myexercise`.
|
||||
4. If an exercise doesn't make sense to you, feel free to open an issue on GitHub!
|
||||
(https://github.com/rust-lang/rustlings/issues/new). We look at every issue,
|
||||
and sometimes, other learners do too so you can help each other out!
|
||||
|
||||
Got all that? Great! To get started, run `rustlings watch` in order to get the first
|
||||
exercise. Make sure to have your editor open!
|
|
@ -4,9 +4,7 @@
|
|||
// was, instead of just sometimes returning `None`. The 2nd test currently
|
||||
// does not compile or pass, but it illustrates the behavior we would like
|
||||
// this function to have.
|
||||
// Execute `rustlings hint errors1` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
// Scroll down for hints!!!
|
||||
|
||||
pub fn generate_nametag_text(name: String) -> Option<String> {
|
||||
if name.len() > 0 {
|
||||
|
@ -40,3 +38,36 @@ mod tests {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// `Err` is one of the variants of `Result`, so what the 2nd test is saying
|
||||
// is that `generate_nametag_text` should return a `Result` instead of an
|
||||
// `Option`.
|
||||
|
||||
// To make this change, you'll need to:
|
||||
// - update the return type in the function signature to be a Result that
|
||||
// could be the variants `Ok(String)` and `Err(String)`
|
||||
// - change the body of the function to return `Ok(stuff)` where it currently
|
||||
// returns `Some(stuff)`
|
||||
// - change the body of the function to return `Err(error message)` where it
|
||||
// currently returns `None`
|
||||
// - change the first test to expect `Ok(stuff)` where it currently expects
|
||||
// `Some(stuff)`.
|
|
@ -14,9 +14,7 @@
|
|||
// and add.
|
||||
|
||||
// There are at least two ways to implement this that are both correct-- but
|
||||
// one is a lot shorter! Execute `rustlings hint errors2` for hints to both ways.
|
||||
|
||||
// I AM NOT DONE
|
||||
// one is a lot shorter! Scroll down for hints to both ways.
|
||||
|
||||
use std::num::ParseIntError;
|
||||
|
||||
|
@ -34,7 +32,10 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn item_quantity_is_a_valid_number() {
|
||||
assert_eq!(total_cost("34"), Ok(171));
|
||||
assert_eq!(
|
||||
total_cost("34"),
|
||||
Ok(171)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -45,3 +46,27 @@ mod tests {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// One way to handle this is using a `match` statement on
|
||||
// `item_quantity.parse::<i32>()` where the cases are `Ok(something)` and
|
||||
// `Err(something)`. This pattern is very common in Rust, though, so there's
|
||||
// a `?` operator that does pretty much what you would make that match statement
|
||||
// do for you! Take a look at this section of the Error Handling chapter:
|
||||
// https://doc.rust-lang.org/stable/book/second-edition/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
|
||||
// and give it a try!
|
62
error_handling/errors3.rs
Normal file
62
error_handling/errors3.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
// errors3.rs
|
||||
// This is a program that is trying to use a completed version of the
|
||||
// `total_cost` function from the previous exercise. It's not working though--
|
||||
// we can't use the `?` operator in the `main()` function! Why not?
|
||||
// What should we do instead? Scroll for hints!
|
||||
|
||||
use std::num::ParseIntError;
|
||||
|
||||
fn main() {
|
||||
let mut tokens = 100;
|
||||
let pretend_user_input = "8";
|
||||
|
||||
let cost = total_cost(pretend_user_input)?;
|
||||
|
||||
if cost > tokens {
|
||||
println!("You can't afford that many!");
|
||||
} else {
|
||||
tokens -= cost;
|
||||
println!("You now have {} tokens.", tokens);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
|
||||
let processing_fee = 1;
|
||||
let cost_per_item = 5;
|
||||
let qty = item_quantity.parse::<i32>()?;
|
||||
|
||||
Ok(qty * cost_per_item + processing_fee)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Since the `?` operator returns an `Err` early if the thing it's trying to
|
||||
// do fails, you can only use the `?` operator in functions that have a
|
||||
// `Result` as their return type.
|
||||
|
||||
// Hence the error that you get if you run this code is:
|
||||
|
||||
// ```
|
||||
// error[E0277]: the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`)
|
||||
// ```
|
||||
|
||||
// So we have to use another way of handling a `Result` within `main`.
|
||||
|
||||
// Decide what we should do if `pretend_user_input` has a string value that does
|
||||
// not parse to an integer, and implement that instead of using the `?`
|
||||
// operator.
|
138
error_handling/errorsn.rs
Normal file
138
error_handling/errorsn.rs
Normal file
|
@ -0,0 +1,138 @@
|
|||
// errorsn.rs
|
||||
// This is a bigger error exercise than the previous ones!
|
||||
// You can do it! :)
|
||||
//
|
||||
// Edit the `read_and_validate` function so that it compiles and
|
||||
// passes the tests... so many things could go wrong!
|
||||
//
|
||||
// - Reading from stdin could produce an io::Error
|
||||
// - Parsing the input could produce a num::ParseIntError
|
||||
// - Validating the input could produce a CreationError (defined below)
|
||||
//
|
||||
// How can we lump these errors into one general error? That is, what
|
||||
// type goes where the question marks are, and how do we return
|
||||
// that type from the body of read_and_validate?
|
||||
//
|
||||
// Scroll down for hints :)
|
||||
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
// PositiveNonzeroInteger is a struct defined below the tests.
|
||||
fn read_and_validate(b: &mut io::BufRead) -> Result<PositiveNonzeroInteger, ???> {
|
||||
let mut line = String::new();
|
||||
b.read_line(&mut line);
|
||||
let num: i64 = line.trim().parse();
|
||||
let answer = PositiveNonzeroInteger::new(num);
|
||||
answer
|
||||
}
|
||||
|
||||
// This is a test helper function that turns a &str into a BufReader.
|
||||
fn test_with_str(s: &str) -> Result<PositiveNonzeroInteger, Box<error::Error>> {
|
||||
let mut b = io::BufReader::new(s.as_bytes());
|
||||
read_and_validate(&mut b)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_success() {
|
||||
let x = test_with_str("42\n");
|
||||
assert_eq!(PositiveNonzeroInteger(42), x.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_num() {
|
||||
let x = test_with_str("eleven billion\n");
|
||||
assert!(x.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_non_positive() {
|
||||
let x = test_with_str("-40\n");
|
||||
assert!(x.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ioerror() {
|
||||
struct Broken;
|
||||
impl io::Read for Broken {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
|
||||
Err(io::Error::new(io::ErrorKind::BrokenPipe, "uh-oh!"))
|
||||
}
|
||||
}
|
||||
let mut b = io::BufReader::new(Broken);
|
||||
assert!(read_and_validate(&mut b).is_err());
|
||||
assert_eq!("uh-oh!", read_and_validate(&mut b).unwrap_err().to_string());
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Debug)]
|
||||
struct PositiveNonzeroInteger(u64);
|
||||
|
||||
impl PositiveNonzeroInteger {
|
||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
||||
if value == 0 {
|
||||
Err(CreationError::Zero)
|
||||
} else if value < 0 {
|
||||
Err(CreationError::Negative)
|
||||
} else {
|
||||
Ok(PositiveNonzeroInteger(value as u64))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_positive_nonzero_integer_creation() {
|
||||
assert!(PositiveNonzeroInteger::new(10).is_ok());
|
||||
assert_eq!(Err(CreationError::Negative), PositiveNonzeroInteger::new(-10));
|
||||
assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0));
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Debug)]
|
||||
enum CreationError {
|
||||
Negative,
|
||||
Zero,
|
||||
}
|
||||
|
||||
impl fmt::Display for CreationError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str((self as &error::Error).description())
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for CreationError {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
CreationError::Negative => "Negative",
|
||||
CreationError::Zero => "Zero",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First hint: To figure out what type should go where the ??? is, take a look
|
||||
// at the test helper function `test_with_str`, since it returns whatever
|
||||
// `read_and_validate` returns and`test_with_str` has its signature fully
|
||||
// specified.
|
||||
|
||||
// Next hint: There are three places in `read_and_validate` that we call a
|
||||
// function that returns a `Result` (that is, the functions might fail).
|
||||
// Apply the `?` operator on those calls so that we return immediately from
|
||||
// `read_and_validate` if those function calls fail.
|
||||
|
||||
// Another hint: under the hood, the `?` operator calls `From::from`
|
||||
// on the error value to convert it to a boxed trait object, a Box<error::Error>,
|
||||
// which is polymorphic-- that means that lots of different kinds of errors
|
||||
// can be returned from the same function because all errors act the same
|
||||
// since they all implement the `error::Error` trait.
|
||||
// Check out this section of the book:
|
||||
// https://doc.rust-lang.org/stable/book/second-edition/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
|
||||
|
||||
// Another another hint: Note that because the `?` operator returns
|
||||
// the *unwrapped* value in the `Ok` case, if we want to return a `Result` from
|
||||
// `read_and_validate` for *its* success case, we'll have to rewrap a value
|
||||
// that we got from the return value of a `?`ed call in an `Ok`-- this will
|
||||
// look like `Ok(something)`.
|
||||
|
||||
// Another another another hint: `Result`s must be "used", that is, you'll
|
||||
// get a warning if you don't handle a `Result` that you get in your
|
||||
// function. Read more about that in the `std::result` module docs:
|
||||
// https://doc.rust-lang.org/std/result/#results-must-be-used
|
45
error_handling/option1.rs
Normal file
45
error_handling/option1.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
// option1.rs
|
||||
// This example panics because the second time it calls `pop`, the `vec`
|
||||
// is empty, so `pop` returns `None`, and `unwrap` panics if it's called
|
||||
// on `None`. Handle this in a more graceful way than calling `unwrap`!
|
||||
// Scroll down for hints :)
|
||||
|
||||
fn main() {
|
||||
let mut list = vec![3];
|
||||
|
||||
let last = list.pop().unwrap();
|
||||
println!("The last item in the list is {:?}", last);
|
||||
|
||||
let second_to_last = list.pop().unwrap();
|
||||
println!("The second-to-last item in the list is {:?}", second_to_last);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Try using a `match` statement where the arms are `Some(thing)` and `None`.
|
||||
// Or set a default value to print out if you get `None` by using the
|
||||
// function `unwrap_or`.
|
||||
// Or use an `if let` statement on the result of `pop()` to both destructure
|
||||
// a `Some` value and only print out something if we have a value!
|
43
error_handling/result1.rs
Normal file
43
error_handling/result1.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
// result1.rs
|
||||
// Make this test pass! Scroll down for hints :)
|
||||
|
||||
#[derive(PartialEq,Debug)]
|
||||
struct PositiveNonzeroInteger(u64);
|
||||
|
||||
#[derive(PartialEq,Debug)]
|
||||
enum CreationError {
|
||||
Negative,
|
||||
Zero,
|
||||
}
|
||||
|
||||
impl PositiveNonzeroInteger {
|
||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
||||
Ok(PositiveNonzeroInteger(value as u64))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_creation() {
|
||||
assert!(PositiveNonzeroInteger::new(10).is_ok());
|
||||
assert_eq!(Err(CreationError::Negative), PositiveNonzeroInteger::new(-10));
|
||||
assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// `PositiveNonzeroInteger::new` is always creating a new instance and returning an `Ok` result.
|
||||
// It should be doing some checking, returning an `Err` result if those checks fail, and only
|
||||
// returning an `Ok` result if those checks determine that everything is... okay :)
|
6
ex1.rs
Normal file
6
ex1.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
// ex1.rs
|
||||
// Make me compile! :)
|
||||
|
||||
fn main() {
|
||||
println();
|
||||
}
|
10
ex2.rs
Normal file
10
ex2.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
// ex2.rs
|
||||
// Make me compile!
|
||||
|
||||
fn something() -> String {
|
||||
"hi!"
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("{}", something());
|
||||
}
|
10
ex3.rs
Normal file
10
ex3.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
// ex3.rs
|
||||
// Make me compile!
|
||||
|
||||
struct Foo {
|
||||
capacity: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", Foo { capacity: 3 });
|
||||
}
|
14
ex4.rs
Normal file
14
ex4.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
// ex4.rs
|
||||
// Make me compile!
|
||||
|
||||
fn something() -> Result<i32, std::num::ParseIntError> {
|
||||
let x:i32 = "3".parse();
|
||||
Ok(x * 4)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match something() {
|
||||
Ok(..) => println!("You win!"),
|
||||
Err(e) => println!("Oh no something went wrong: {}", e),
|
||||
}
|
||||
}
|
22
ex5.rs
Normal file
22
ex5.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
// ex5.rs
|
||||
// Make me compile!
|
||||
|
||||
enum Reaction<'a> {
|
||||
Sad(&'a str),
|
||||
Happy(&'a str),
|
||||
}
|
||||
|
||||
fn express(sentiment: Reaction) {
|
||||
match sentiment {
|
||||
Reaction::Sad(s) => println!(":( {}", s),
|
||||
Reaction::Happy(s) => println!(":) {}", s),
|
||||
}
|
||||
}
|
||||
|
||||
fn main () {
|
||||
let x = Reaction::Happy("It's a great day for Rust!");
|
||||
express(x);
|
||||
express(x);
|
||||
let y = Reaction::Sad("This code doesn't compile yet.");
|
||||
express(y);
|
||||
}
|
47
ex6.rs
Normal file
47
ex6.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
// ex6.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
|
||||
fn main() {
|
||||
let robot_name = Some(String::from("Bors"));
|
||||
|
||||
match robot_name {
|
||||
Some(name) => println!("Found a name: {}", name),
|
||||
None => (),
|
||||
}
|
||||
|
||||
println!("robot_name is: {:?}", robot_name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Hint: The following two statements are equivalent:
|
||||
// let x = &y;
|
||||
// let ref x = y;
|
|
@ -1,24 +0,0 @@
|
|||
# Exercise to Book Chapter mapping
|
||||
|
||||
| Exercise | Book Chapter |
|
||||
|------------------------|--------------|
|
||||
| variables | §3.1 |
|
||||
| functions | §3.3 |
|
||||
| if | §3.5 |
|
||||
| move_semantics | §4.1 |
|
||||
| primitive_types | §4.3 |
|
||||
| structs | §5.1 |
|
||||
| enums | §6 |
|
||||
| modules | §7 |
|
||||
| collections | §8.1, §8.3 |
|
||||
| strings | §8.2 |
|
||||
| error_handling | §9 |
|
||||
| generics | §10 |
|
||||
| option | §10.1 |
|
||||
| traits | §10.2 |
|
||||
| tests | §11.1 |
|
||||
| standard_library_types | §13.2 |
|
||||
| threads | §16.1 |
|
||||
| macros | §19.6 |
|
||||
| clippy | n/a |
|
||||
| conversions | n/a |
|
|
@ -1,98 +0,0 @@
|
|||
// advanced_errs1.rs
|
||||
|
||||
// Remember back in errors6, we had multiple mapping functions so that we
|
||||
// could translate lower-level errors into our custom error type using
|
||||
// `map_err()`? What if we could use the `?` operator directly instead?
|
||||
|
||||
// Make this code compile! Execute `rustlings hint advanced_errs1` for
|
||||
// hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::num::ParseIntError;
|
||||
use std::str::FromStr;
|
||||
|
||||
// This is a custom error type that we will be using in the `FromStr`
|
||||
// implementation.
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum ParsePosNonzeroError {
|
||||
Creation(CreationError),
|
||||
ParseInt(ParseIntError),
|
||||
}
|
||||
|
||||
impl From<CreationError> for ParsePosNonzeroError {
|
||||
fn from(e: CreationError) -> Self {
|
||||
// TODO: complete this implementation so that the `?` operator will
|
||||
// work for `CreationError`
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: implement another instance of the `From` trait here so that the
|
||||
// `?` operator will work in the other place in the `FromStr`
|
||||
// implementation below.
|
||||
|
||||
// Don't change anything below this line.
|
||||
|
||||
impl FromStr for PositiveNonzeroInteger {
|
||||
type Err = ParsePosNonzeroError;
|
||||
fn from_str(s: &str) -> Result<PositiveNonzeroInteger, Self::Err> {
|
||||
let x: i64 = s.parse()?;
|
||||
Ok(PositiveNonzeroInteger::new(x)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct PositiveNonzeroInteger(u64);
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum CreationError {
|
||||
Negative,
|
||||
Zero,
|
||||
}
|
||||
|
||||
impl PositiveNonzeroInteger {
|
||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
||||
match value {
|
||||
x if x < 0 => Err(CreationError::Negative),
|
||||
x if x == 0 => Err(CreationError::Zero),
|
||||
x => Ok(PositiveNonzeroInteger(x as u64)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_error() {
|
||||
// We can't construct a ParseIntError, so we have to pattern match.
|
||||
assert!(matches!(
|
||||
PositiveNonzeroInteger::from_str("not a number"),
|
||||
Err(ParsePosNonzeroError::ParseInt(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative() {
|
||||
assert_eq!(
|
||||
PositiveNonzeroInteger::from_str("-555"),
|
||||
Err(ParsePosNonzeroError::Creation(CreationError::Negative))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero() {
|
||||
assert_eq!(
|
||||
PositiveNonzeroInteger::from_str("0"),
|
||||
Err(ParsePosNonzeroError::Creation(CreationError::Zero))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_positive() {
|
||||
let x = PositiveNonzeroInteger::new(42);
|
||||
assert!(x.is_ok());
|
||||
assert_eq!(PositiveNonzeroInteger::from_str("42"), Ok(x.unwrap()));
|
||||
}
|
||||
}
|
|
@ -1,202 +0,0 @@
|
|||
// advanced_errs2.rs
|
||||
|
||||
// This exercise demonstrates a few traits that are useful for custom error
|
||||
// types to implement, especially so that other code can consume the custom
|
||||
// error type more usefully.
|
||||
|
||||
// Make this compile, and make the tests pass!
|
||||
// Execute `rustlings hint advanced_errs2` for hints.
|
||||
|
||||
// Steps:
|
||||
// 1. Implement a missing trait so that `main()` will compile.
|
||||
// 2. Complete the partial implementation of `From` for
|
||||
// `ParseClimateError`.
|
||||
// 3. Handle the missing error cases in the `FromStr` implementation for
|
||||
// `Climate`.
|
||||
// 4. Complete the partial implementation of `Display` for
|
||||
// `ParseClimateError`.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::num::{ParseFloatError, ParseIntError};
|
||||
use std::str::FromStr;
|
||||
|
||||
// This is the custom error type that we will be using for the parser for
|
||||
// `Climate`.
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum ParseClimateError {
|
||||
Empty,
|
||||
BadLen,
|
||||
NoCity,
|
||||
ParseInt(ParseIntError),
|
||||
ParseFloat(ParseFloatError),
|
||||
}
|
||||
|
||||
// This `From` implementation allows the `?` operator to work on
|
||||
// `ParseIntError` values.
|
||||
impl From<ParseIntError> for ParseClimateError {
|
||||
fn from(e: ParseIntError) -> Self {
|
||||
Self::ParseInt(e)
|
||||
}
|
||||
}
|
||||
|
||||
// This `From` implementation allows the `?` operator to work on
|
||||
// `ParseFloatError` values.
|
||||
impl From<ParseFloatError> for ParseClimateError {
|
||||
fn from(e: ParseFloatError) -> Self {
|
||||
// TODO: Complete this function
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Implement a missing trait so that `main()` below will compile. It
|
||||
// is not necessary to implement any methods inside the missing trait.
|
||||
|
||||
// The `Display` trait allows for other code to obtain the error formatted
|
||||
// as a user-visible string.
|
||||
impl Display for ParseClimateError {
|
||||
// TODO: Complete this function so that it produces the correct strings
|
||||
// for each error variant.
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
// Imports the variants to make the following code more compact.
|
||||
use ParseClimateError::*;
|
||||
match self {
|
||||
NoCity => write!(f, "no city name"),
|
||||
ParseFloat(e) => write!(f, "error parsing temperature: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct Climate {
|
||||
city: String,
|
||||
year: u32,
|
||||
temp: f32,
|
||||
}
|
||||
|
||||
// Parser for `Climate`.
|
||||
// 1. Split the input string into 3 fields: city, year, temp.
|
||||
// 2. Return an error if the string is empty or has the wrong number of
|
||||
// fields.
|
||||
// 3. Return an error if the city name is empty.
|
||||
// 4. Parse the year as a `u32` and return an error if that fails.
|
||||
// 5. Parse the temp as a `f32` and return an error if that fails.
|
||||
// 6. Return an `Ok` value containing the completed `Climate` value.
|
||||
impl FromStr for Climate {
|
||||
type Err = ParseClimateError;
|
||||
// TODO: Complete this function by making it handle the missing error
|
||||
// cases.
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let v: Vec<_> = s.split(',').collect();
|
||||
let (city, year, temp) = match &v[..] {
|
||||
[city, year, temp] => (city.to_string(), year, temp),
|
||||
_ => return Err(ParseClimateError::BadLen),
|
||||
};
|
||||
let year: u32 = year.parse()?;
|
||||
let temp: f32 = temp.parse()?;
|
||||
Ok(Climate { city, year, temp })
|
||||
}
|
||||
}
|
||||
|
||||
// Don't change anything below this line (other than to enable ignored
|
||||
// tests).
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
println!("{:?}", "Hong Kong,1999,25.7".parse::<Climate>()?);
|
||||
println!("{:?}", "".parse::<Climate>()?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_empty() {
|
||||
let res = "".parse::<Climate>();
|
||||
assert_eq!(res, Err(ParseClimateError::Empty));
|
||||
assert_eq!(res.unwrap_err().to_string(), "empty input");
|
||||
}
|
||||
#[test]
|
||||
fn test_short() {
|
||||
let res = "Boston,1991".parse::<Climate>();
|
||||
assert_eq!(res, Err(ParseClimateError::BadLen));
|
||||
assert_eq!(res.unwrap_err().to_string(), "incorrect number of fields");
|
||||
}
|
||||
#[test]
|
||||
fn test_long() {
|
||||
let res = "Paris,1920,17.2,extra".parse::<Climate>();
|
||||
assert_eq!(res, Err(ParseClimateError::BadLen));
|
||||
assert_eq!(res.unwrap_err().to_string(), "incorrect number of fields");
|
||||
}
|
||||
#[test]
|
||||
fn test_no_city() {
|
||||
let res = ",1997,20.5".parse::<Climate>();
|
||||
assert_eq!(res, Err(ParseClimateError::NoCity));
|
||||
assert_eq!(res.unwrap_err().to_string(), "no city name");
|
||||
}
|
||||
#[test]
|
||||
fn test_parse_int_neg() {
|
||||
let res = "Barcelona,-25,22.3".parse::<Climate>();
|
||||
assert!(matches!(res, Err(ParseClimateError::ParseInt(_))));
|
||||
let err = res.unwrap_err();
|
||||
if let ParseClimateError::ParseInt(ref inner) = err {
|
||||
assert_eq!(
|
||||
err.to_string(),
|
||||
format!("error parsing year: {}", inner.to_string())
|
||||
);
|
||||
} else {
|
||||
unreachable!();
|
||||
};
|
||||
}
|
||||
#[test]
|
||||
fn test_parse_int_bad() {
|
||||
let res = "Beijing,foo,15.0".parse::<Climate>();
|
||||
assert!(matches!(res, Err(ParseClimateError::ParseInt(_))));
|
||||
let err = res.unwrap_err();
|
||||
if let ParseClimateError::ParseInt(ref inner) = err {
|
||||
assert_eq!(
|
||||
err.to_string(),
|
||||
format!("error parsing year: {}", inner.to_string())
|
||||
);
|
||||
} else {
|
||||
unreachable!();
|
||||
};
|
||||
}
|
||||
#[test]
|
||||
fn test_parse_float() {
|
||||
let res = "Manila,2001,bar".parse::<Climate>();
|
||||
assert!(matches!(res, Err(ParseClimateError::ParseFloat(_))));
|
||||
let err = res.unwrap_err();
|
||||
if let ParseClimateError::ParseFloat(ref inner) = err {
|
||||
assert_eq!(
|
||||
err.to_string(),
|
||||
format!("error parsing temperature: {}", inner.to_string())
|
||||
);
|
||||
} else {
|
||||
unreachable!();
|
||||
};
|
||||
}
|
||||
#[test]
|
||||
fn test_parse_good() {
|
||||
let res = "Munich,2015,23.1".parse::<Climate>();
|
||||
assert_eq!(
|
||||
res,
|
||||
Ok(Climate {
|
||||
city: "Munich".to_string(),
|
||||
year: 2015,
|
||||
temp: 23.1,
|
||||
})
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_downcast() {
|
||||
let res = "São Paulo,-21,28.5".parse::<Climate>();
|
||||
assert!(matches!(res, Err(ParseClimateError::ParseInt(_))));
|
||||
let err = res.unwrap_err();
|
||||
let inner: Option<&(dyn Error + 'static)> = err.source();
|
||||
assert!(inner.is_some());
|
||||
assert!(inner.unwrap().is::<ParseIntError>());
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
# Clippy
|
||||
|
||||
The Clippy tool is a collection of lints to analyze your code so you can catch common mistakes and improve your Rust code.
|
||||
|
||||
If you used the installation script for Rustlings, Clippy should be already installed.
|
||||
If not you can install it manually via `rustup component add clippy`.
|
||||
|
||||
## Further information
|
||||
|
||||
- [GitHub Repository](https://github.com/rust-lang/rust-clippy).
|
|
@ -1,17 +0,0 @@
|
|||
// clippy1.rs
|
||||
// The Clippy tool is a collection of lints to analyze your code
|
||||
// so you can catch common mistakes and improve your Rust code.
|
||||
//
|
||||
// For these exercises the code will fail to compile when there are clippy warnings
|
||||
// check clippy's suggestions from the output to solve the exercise.
|
||||
// Execute `rustlings hint clippy1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let x = 1.2331f64;
|
||||
let y = 1.2332f64;
|
||||
if y != x {
|
||||
println!("Success!");
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
// clippy2.rs
|
||||
// Make me compile! Execute `rustlings hint clippy2` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let mut res = 42;
|
||||
let option = Some(12);
|
||||
for x in option {
|
||||
res += x;
|
||||
}
|
||||
println!("{}", res);
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
# Collections
|
||||
|
||||
Rust’s standard library includes a number of very useful data
|
||||
structures called collections. Most other data types represent one
|
||||
specific value, but collections can contain multiple values. Unlike
|
||||
the built-in array and tuple types, the data these collections point
|
||||
to is stored on the heap, which means the amount of data does not need
|
||||
to be known at compile time and can grow or shrink as the program
|
||||
runs.
|
||||
|
||||
This exercise will get you familiar with two fundamental data
|
||||
structures that are used very often in Rust programs:
|
||||
|
||||
* A *vector* allows you to store a variable number of values next to
|
||||
each other.
|
||||
* A *hash map* allows you to associate a value with a particular key.
|
||||
You may also know this by the names [*unordered map* in C++](https://en.cppreference.com/w/cpp/container/unordered_map),
|
||||
[*dictionary* in Python](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) or an *associative array* in other languages.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Storing Lists of Values with Vectors](https://doc.rust-lang.org/stable/book/ch08-01-vectors.html)
|
||||
- [Storing Keys with Associated Values in Hash Maps](https://doc.rust-lang.org/book/ch08-03-hash-maps.html)
|
|
@ -1,44 +0,0 @@
|
|||
// hashmap1.rs
|
||||
// A basket of fruits in the form of a hash map needs to be defined.
|
||||
// The key represents the name of the fruit and the value represents
|
||||
// how many of that particular fruit is in the basket. You have to put
|
||||
// at least three different types of fruits (e.g apple, banana, mango)
|
||||
// in the basket and the total count of all the fruits should be at
|
||||
// least five.
|
||||
//
|
||||
// Make me compile and pass the tests!
|
||||
//
|
||||
// Execute the command `rustlings hint hashmap1` if you need
|
||||
// hints.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn fruit_basket() -> HashMap<String, u32> {
|
||||
let mut basket = // TODO: declare your hash map here.
|
||||
|
||||
// Two bananas are already given for you :)
|
||||
basket.insert(String::from("banana"), 2);
|
||||
|
||||
// TODO: Put more fruits in your basket here.
|
||||
|
||||
basket
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn at_least_three_types_of_fruits() {
|
||||
let basket = fruit_basket();
|
||||
assert!(basket.len() >= 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn at_least_five_fruits() {
|
||||
let basket = fruit_basket();
|
||||
assert!(basket.values().sum::<u32>() >= 5);
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
// hashmap2.rs
|
||||
|
||||
// A basket of fruits in the form of a hash map is given. The key
|
||||
// represents the name of the fruit and the value represents how many
|
||||
// of that particular fruit is in the basket. You have to put *MORE
|
||||
// THAN 11* fruits in the basket. Three types of fruits - Apple (4),
|
||||
// Mango (2) and Lychee (5) are already given in the basket. You are
|
||||
// not allowed to insert any more of these fruits!
|
||||
//
|
||||
// Make me pass the tests!
|
||||
//
|
||||
// Execute the command `rustlings hint hashmap2` if you need
|
||||
// hints.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
enum Fruit {
|
||||
Apple,
|
||||
Banana,
|
||||
Mango,
|
||||
Lychee,
|
||||
Pineapple,
|
||||
}
|
||||
|
||||
fn fruit_basket(basket: &mut HashMap<Fruit, u32>) {
|
||||
let fruit_kinds = vec![
|
||||
Fruit::Apple,
|
||||
Fruit::Banana,
|
||||
Fruit::Mango,
|
||||
Fruit::Lychee,
|
||||
Fruit::Pineapple,
|
||||
];
|
||||
|
||||
for fruit in fruit_kinds {
|
||||
// TODO: Put new fruits if not already present. Note that you
|
||||
// are not allowed to put any type of fruit that's already
|
||||
// present!
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn get_fruit_basket() -> HashMap<Fruit, u32> {
|
||||
let mut basket = HashMap::<Fruit, u32>::new();
|
||||
basket.insert(Fruit::Apple, 4);
|
||||
basket.insert(Fruit::Mango, 2);
|
||||
basket.insert(Fruit::Lychee, 5);
|
||||
|
||||
basket
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_given_fruits_are_not_modified() {
|
||||
let mut basket = get_fruit_basket();
|
||||
fruit_basket(&mut basket);
|
||||
assert_eq!(*basket.get(&Fruit::Apple).unwrap(), 4);
|
||||
assert_eq!(*basket.get(&Fruit::Mango).unwrap(), 2);
|
||||
assert_eq!(*basket.get(&Fruit::Lychee).unwrap(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn at_least_five_types_of_fruits() {
|
||||
let mut basket = get_fruit_basket();
|
||||
fruit_basket(&mut basket);
|
||||
let count_fruit_kinds = basket.len();
|
||||
assert!(count_fruit_kinds >= 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn greater_than_eleven_fruits() {
|
||||
let mut basket = get_fruit_basket();
|
||||
fruit_basket(&mut basket);
|
||||
let count = basket.values().sum::<u32>();
|
||||
assert!(count > 11);
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// vec1.rs
|
||||
// Your task is to create a `Vec` which holds the exact same elements
|
||||
// as in the array `a`.
|
||||
// Make me compile and pass the test!
|
||||
// Execute the command `rustlings hint vec1` if you need hints.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn array_and_vec() -> ([i32; 4], Vec<i32>) {
|
||||
let a = [10, 20, 30, 40]; // a plain array
|
||||
let v = // TODO: declare your vector here with the macro for vectors
|
||||
|
||||
(a, v)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_array_and_vec_similarity() {
|
||||
let (a, v) = array_and_vec();
|
||||
assert_eq!(a, v[..]);
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
// vec2.rs
|
||||
// A Vec of even numbers is given. Your task is to complete the loop
|
||||
// so that each number in the Vec is multiplied by 2.
|
||||
//
|
||||
// Make me pass the test!
|
||||
//
|
||||
// Execute the command `rustlings hint vec2` if you need
|
||||
// hints.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn vec_loop(mut v: Vec<i32>) -> Vec<i32> {
|
||||
for i in v.iter_mut() {
|
||||
// TODO: Fill this up so that each element in the Vec `v` is
|
||||
// multiplied by 2.
|
||||
}
|
||||
|
||||
// At this point, `v` should be equal to [4, 8, 12, 16, 20].
|
||||
v
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_vec_loop() {
|
||||
let v: Vec<i32> = (1..).filter(|x| x % 2 == 0).take(5).collect();
|
||||
let ans = vec_loop(v.clone());
|
||||
|
||||
assert_eq!(ans, v.iter().map(|x| x * 2).collect::<Vec<i32>>());
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
# Type conversions
|
||||
|
||||
Rust offers a multitude of ways to convert a value of a given type into another type.
|
||||
|
||||
The simplest form of type conversion is a type cast expression. It is denoted with the binary operator `as`. For instance, `println!("{}", 1 + 1.0);` would not compile, since `1` is an integer while `1.0` is a float. However, `println!("{}", 1 as f32 + 1.0)` should compile. The exercise [`using_as`](using_as.rs) tries to cover this.
|
||||
|
||||
Rust also offers traits that facilitate type conversions upon implementation. These traits can be found under the [`convert`](https://doc.rust-lang.org/std/convert/index.html) module.
|
||||
The traits are the following:
|
||||
- `From` and `Into` covered in [`from_into`](from_into.rs)
|
||||
- `TryFrom` and `TryInto` covered in [`try_from_into`](try_from_into.rs)
|
||||
- `AsRef` and `AsMut` covered in [`as_ref_mut`](as_ref_mut.rs)
|
||||
|
||||
Furthermore, the `std::str` module offers a trait called [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) which helps with converting strings into target types via the `parse` method on strings. If properly implemented for a given type `Person`, then `let p: Person = "Mark,20".parse().unwrap()` should both compile and run without panicking.
|
||||
|
||||
These should be the main ways ***within the standard library*** to convert data into your desired types.
|
||||
|
||||
## Further information
|
||||
|
||||
These are not directly covered in the book, but the standard library has a great documentation for it.
|
||||
- [conversions](https://doc.rust-lang.org/std/convert/index.html)
|
||||
- [`FromStr` trait](https://doc.rust-lang.org/std/str/trait.FromStr.html)
|
|
@ -1,52 +0,0 @@
|
|||
// AsRef and AsMut allow for cheap reference-to-reference conversions.
|
||||
// Read more about them at https://doc.rust-lang.org/std/convert/trait.AsRef.html
|
||||
// and https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// Obtain the number of bytes (not characters) in the given argument
|
||||
// Add the AsRef trait appropriately as a trait bound
|
||||
fn byte_counter<T>(arg: T) -> usize {
|
||||
arg.as_ref().as_bytes().len()
|
||||
}
|
||||
|
||||
// Obtain the number of characters (not bytes) in the given argument
|
||||
// Add the AsRef trait appropriately as a trait bound
|
||||
fn char_counter<T>(arg: T) -> usize {
|
||||
arg.as_ref().chars().count()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = "Café au lait";
|
||||
println!("{}", char_counter(s));
|
||||
println!("{}", byte_counter(s));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn different_counts() {
|
||||
let s = "Café au lait";
|
||||
assert_ne!(char_counter(s), byte_counter(s));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_counts() {
|
||||
let s = "Cafe au lait";
|
||||
assert_eq!(char_counter(s), byte_counter(s));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn different_counts_using_string() {
|
||||
let s = String::from("Café au lait");
|
||||
assert_ne!(char_counter(s.clone()), byte_counter(s));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_counts_using_string() {
|
||||
let s = String::from("Cafe au lait");
|
||||
assert_eq!(char_counter(s.clone()), byte_counter(s));
|
||||
}
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
// The From trait is used for value-to-value conversions.
|
||||
// If From is implemented correctly for a type, the Into trait should work conversely.
|
||||
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.From.html
|
||||
#[derive(Debug)]
|
||||
struct Person {
|
||||
name: String,
|
||||
age: usize,
|
||||
}
|
||||
|
||||
// We implement the Default trait to use it as a fallback
|
||||
// when the provided string is not convertible into a Person object
|
||||
impl Default for Person {
|
||||
fn default() -> Person {
|
||||
Person {
|
||||
name: String::from("John"),
|
||||
age: 30,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Your task is to complete this implementation
|
||||
// in order for the line `let p = Person::from("Mark,20")` to compile
|
||||
// Please note that you'll need to parse the age component into a `usize`
|
||||
// with something like `"4".parse::<usize>()`. The outcome of this needs to
|
||||
// be handled appropriately.
|
||||
//
|
||||
// Steps:
|
||||
// 1. If the length of the provided string is 0, then return the default of Person
|
||||
// 2. Split the given string on the commas present in it
|
||||
// 3. Extract the first element from the split operation and use it as the name
|
||||
// 4. If the name is empty, then return the default of Person
|
||||
// 5. Extract the other element from the split operation and parse it into a `usize` as the age
|
||||
// If while parsing the age, something goes wrong, then return the default of Person
|
||||
// Otherwise, then return an instantiated Person object with the results
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
impl From<&str> for Person {
|
||||
fn from(s: &str) -> Person {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Use the `from` function
|
||||
let p1 = Person::from("Mark,20");
|
||||
// Since From is implemented for Person, we should be able to use Into
|
||||
let p2: Person = "Gerald,70".into();
|
||||
println!("{:?}", p1);
|
||||
println!("{:?}", p2);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_default() {
|
||||
// Test that the default person is 30 year old John
|
||||
let dp = Person::default();
|
||||
assert_eq!(dp.name, "John");
|
||||
assert_eq!(dp.age, 30);
|
||||
}
|
||||
#[test]
|
||||
fn test_bad_convert() {
|
||||
// Test that John is returned when bad string is provided
|
||||
let p = Person::from("");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
#[test]
|
||||
fn test_good_convert() {
|
||||
// Test that "Mark,20" works
|
||||
let p = Person::from("Mark,20");
|
||||
assert_eq!(p.name, "Mark");
|
||||
assert_eq!(p.age, 20);
|
||||
}
|
||||
#[test]
|
||||
fn test_bad_age() {
|
||||
// Test that "Mark,twenty" will return the default person due to an error in parsing age
|
||||
let p = Person::from("Mark,twenty");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_comma_and_age() {
|
||||
let p: Person = Person::from("Mark");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_age() {
|
||||
let p: Person = Person::from("Mark,");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_name() {
|
||||
let p: Person = Person::from(",1");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_name_and_age() {
|
||||
let p: Person = Person::from(",");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_name_and_invalid_age() {
|
||||
let p: Person = Person::from(",one");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trailing_comma() {
|
||||
let p: Person = Person::from("Mike,32,");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trailing_comma_and_some_string() {
|
||||
let p: Person = Person::from("Mike,32,man");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
// from_str.rs
|
||||
// This is similar to from_into.rs, but this time we'll implement `FromStr`
|
||||
// and return errors instead of falling back to a default value.
|
||||
// Additionally, upon implementing FromStr, you can use the `parse` method
|
||||
// on strings to generate an object of the implementor type.
|
||||
// You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html
|
||||
use std::num::ParseIntError;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct Person {
|
||||
name: String,
|
||||
age: usize,
|
||||
}
|
||||
|
||||
// We will use this error type for the `FromStr` implementation.
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum ParsePersonError {
|
||||
// Empty input string
|
||||
Empty,
|
||||
// Incorrect number of fields
|
||||
BadLen,
|
||||
// Empty name field
|
||||
NoName,
|
||||
// Wrapped error from parse::<usize>()
|
||||
ParseInt(ParseIntError),
|
||||
}
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// Steps:
|
||||
// 1. If the length of the provided string is 0, an error should be returned
|
||||
// 2. Split the given string on the commas present in it
|
||||
// 3. Only 2 elements should be returned from the split, otherwise return an error
|
||||
// 4. Extract the first element from the split operation and use it as the name
|
||||
// 5. Extract the other element from the split operation and parse it into a `usize` as the age
|
||||
// with something like `"4".parse::<usize>()`
|
||||
// 6. If while extracting the name and the age something goes wrong, an error should be returned
|
||||
// If everything goes well, then return a Result of a Person object
|
||||
|
||||
impl FromStr for Person {
|
||||
type Err = ParsePersonError;
|
||||
fn from_str(s: &str) -> Result<Person, Self::Err> {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let p = "Mark,20".parse::<Person>().unwrap();
|
||||
println!("{:?}", p);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn empty_input() {
|
||||
assert_eq!("".parse::<Person>(), Err(ParsePersonError::Empty));
|
||||
}
|
||||
#[test]
|
||||
fn good_input() {
|
||||
let p = "John,32".parse::<Person>();
|
||||
assert!(p.is_ok());
|
||||
let p = p.unwrap();
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 32);
|
||||
}
|
||||
#[test]
|
||||
fn missing_age() {
|
||||
assert!(matches!(
|
||||
"John,".parse::<Person>(),
|
||||
Err(ParsePersonError::ParseInt(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_age() {
|
||||
assert!(matches!(
|
||||
"John,twenty".parse::<Person>(),
|
||||
Err(ParsePersonError::ParseInt(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_comma_and_age() {
|
||||
assert_eq!("John".parse::<Person>(), Err(ParsePersonError::BadLen));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_name() {
|
||||
assert_eq!(",1".parse::<Person>(), Err(ParsePersonError::NoName));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_name_and_age() {
|
||||
assert!(matches!(
|
||||
",".parse::<Person>(),
|
||||
Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_name_and_invalid_age() {
|
||||
assert!(matches!(
|
||||
",one".parse::<Person>(),
|
||||
Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_comma() {
|
||||
assert_eq!("John,32,".parse::<Person>(), Err(ParsePersonError::BadLen));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_comma_and_some_string() {
|
||||
assert_eq!(
|
||||
"John,32,man".parse::<Person>(),
|
||||
Err(ParsePersonError::BadLen)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
// try_from_into.rs
|
||||
// TryFrom is a simple and safe type conversion that may fail in a controlled way under some circumstances.
|
||||
// Basically, this is the same as From. The main difference is that this should return a Result type
|
||||
// instead of the target type itself.
|
||||
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct Color {
|
||||
red: u8,
|
||||
green: u8,
|
||||
blue: u8,
|
||||
}
|
||||
|
||||
// We will use this error type for these `TryFrom` conversions.
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum IntoColorError {
|
||||
// Incorrect length of slice
|
||||
BadLen,
|
||||
// Integer conversion error
|
||||
IntConversion,
|
||||
}
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// Your task is to complete this implementation
|
||||
// and return an Ok result of inner type Color.
|
||||
// You need to create an implementation for a tuple of three integers,
|
||||
// an array of three integers, and a slice of integers.
|
||||
//
|
||||
// Note that the implementation for tuple and array will be checked at compile time,
|
||||
// but the slice implementation needs to check the slice length!
|
||||
// Also note that correct RGB color values must be integers in the 0..=255 range.
|
||||
|
||||
// Tuple implementation
|
||||
impl TryFrom<(i16, i16, i16)> for Color {
|
||||
type Error = IntoColorError;
|
||||
fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {
|
||||
}
|
||||
}
|
||||
|
||||
// Array implementation
|
||||
impl TryFrom<[i16; 3]> for Color {
|
||||
type Error = IntoColorError;
|
||||
fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {
|
||||
}
|
||||
}
|
||||
|
||||
// Slice implementation
|
||||
impl TryFrom<&[i16]> for Color {
|
||||
type Error = IntoColorError;
|
||||
fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Use the `from` function
|
||||
let c1 = Color::try_from((183, 65, 14));
|
||||
println!("{:?}", c1);
|
||||
|
||||
// Since TryFrom is implemented for Color, we should be able to use TryInto
|
||||
let c2: Result<Color, _> = [183, 65, 14].try_into();
|
||||
println!("{:?}", c2);
|
||||
|
||||
let v = vec![183, 65, 14];
|
||||
// With slice we should use `try_from` function
|
||||
let c3 = Color::try_from(&v[..]);
|
||||
println!("{:?}", c3);
|
||||
// or take slice within round brackets and use TryInto
|
||||
let c4: Result<Color, _> = (&v[..]).try_into();
|
||||
println!("{:?}", c4);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_tuple_out_of_range_positive() {
|
||||
assert_eq!(
|
||||
Color::try_from((256, 1000, 10000)),
|
||||
Err(IntoColorError::IntConversion)
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_tuple_out_of_range_negative() {
|
||||
assert_eq!(
|
||||
Color::try_from((-1, -10, -256)),
|
||||
Err(IntoColorError::IntConversion)
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_tuple_sum() {
|
||||
assert_eq!(
|
||||
Color::try_from((-1, 255, 255)),
|
||||
Err(IntoColorError::IntConversion)
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_tuple_correct() {
|
||||
let c: Result<Color, _> = (183, 65, 14).try_into();
|
||||
assert!(c.is_ok());
|
||||
assert_eq!(
|
||||
c.unwrap(),
|
||||
Color {
|
||||
red: 183,
|
||||
green: 65,
|
||||
blue: 14
|
||||
}
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_array_out_of_range_positive() {
|
||||
let c: Result<Color, _> = [1000, 10000, 256].try_into();
|
||||
assert_eq!(c, Err(IntoColorError::IntConversion));
|
||||
}
|
||||
#[test]
|
||||
fn test_array_out_of_range_negative() {
|
||||
let c: Result<Color, _> = [-10, -256, -1].try_into();
|
||||
assert_eq!(c, Err(IntoColorError::IntConversion));
|
||||
}
|
||||
#[test]
|
||||
fn test_array_sum() {
|
||||
let c: Result<Color, _> = [-1, 255, 255].try_into();
|
||||
assert_eq!(c, Err(IntoColorError::IntConversion));
|
||||
}
|
||||
#[test]
|
||||
fn test_array_correct() {
|
||||
let c: Result<Color, _> = [183, 65, 14].try_into();
|
||||
assert!(c.is_ok());
|
||||
assert_eq!(
|
||||
c.unwrap(),
|
||||
Color {
|
||||
red: 183,
|
||||
green: 65,
|
||||
blue: 14
|
||||
}
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_slice_out_of_range_positive() {
|
||||
let arr = [10000, 256, 1000];
|
||||
assert_eq!(
|
||||
Color::try_from(&arr[..]),
|
||||
Err(IntoColorError::IntConversion)
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_slice_out_of_range_negative() {
|
||||
let arr = [-256, -1, -10];
|
||||
assert_eq!(
|
||||
Color::try_from(&arr[..]),
|
||||
Err(IntoColorError::IntConversion)
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_slice_sum() {
|
||||
let arr = [-1, 255, 255];
|
||||
assert_eq!(
|
||||
Color::try_from(&arr[..]),
|
||||
Err(IntoColorError::IntConversion)
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_slice_correct() {
|
||||
let v = vec![183, 65, 14];
|
||||
let c: Result<Color, _> = Color::try_from(&v[..]);
|
||||
assert!(c.is_ok());
|
||||
assert_eq!(
|
||||
c.unwrap(),
|
||||
Color {
|
||||
red: 183,
|
||||
green: 65,
|
||||
blue: 14
|
||||
}
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_slice_excess_length() {
|
||||
let v = vec![0, 0, 0, 0];
|
||||
assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen));
|
||||
}
|
||||
#[test]
|
||||
fn test_slice_insufficient_length() {
|
||||
let v = vec![0, 0];
|
||||
assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen));
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
// Type casting in Rust is done via the usage of the `as` operator.
|
||||
// Please note that the `as` operator is not only used when type casting.
|
||||
// It also helps with renaming imports.
|
||||
//
|
||||
// The goal is to make sure that the division does not fail to compile
|
||||
// and returns the proper type.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn average(values: &[f64]) -> f64 {
|
||||
let total = values.iter().fold(0.0, |a, b| a + b);
|
||||
total / values.len()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let values = [3.5, 0.3, 13.0, 11.7];
|
||||
println!("{}", average(&values));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn returns_proper_type_and_value() {
|
||||
assert_eq!(average(&[3.5, 0.3, 13.0, 11.7]), 7.125);
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
# Enums
|
||||
|
||||
Rust allows you to define types called "enums" which enumerate possible values.
|
||||
Enums are a feature in many languages, but their capabilities differ in each language. Rust’s enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell.
|
||||
Useful in combination with enums is Rust's "pattern matching" facility, which makes it easy to run different code for different values of an enumeration.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html)
|
||||
- [Pattern syntax](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html)
|
|
@ -1,16 +0,0 @@
|
|||
// enums1.rs
|
||||
// Make me compile! Execute `rustlings hint enums1` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Message {
|
||||
// TODO: define a few types of messages as used below
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", Message::Quit);
|
||||
println!("{:?}", Message::Echo);
|
||||
println!("{:?}", Message::Move);
|
||||
println!("{:?}", Message::ChangeColor);
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
// enums2.rs
|
||||
// Make me compile! Execute `rustlings hint enums2` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Message {
|
||||
// TODO: define the different variants used below
|
||||
}
|
||||
|
||||
impl Message {
|
||||
fn call(&self) {
|
||||
println!("{:?}", &self);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let messages = [
|
||||
Message::Move { x: 10, y: 30 },
|
||||
Message::Echo(String::from("hello world")),
|
||||
Message::ChangeColor(200, 255, 255),
|
||||
Message::Quit,
|
||||
];
|
||||
|
||||
for message in &messages {
|
||||
message.call();
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
// enums3.rs
|
||||
// Address all the TODOs to make the tests pass!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
enum Message {
|
||||
// TODO: implement the message variant types based on their usage below
|
||||
}
|
||||
|
||||
struct Point {
|
||||
x: u8,
|
||||
y: u8,
|
||||
}
|
||||
|
||||
struct State {
|
||||
color: (u8, u8, u8),
|
||||
position: Point,
|
||||
quit: bool,
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn change_color(&mut self, color: (u8, u8, u8)) {
|
||||
self.color = color;
|
||||
}
|
||||
|
||||
fn quit(&mut self) {
|
||||
self.quit = true;
|
||||
}
|
||||
|
||||
fn echo(&self, s: String) {
|
||||
println!("{}", s);
|
||||
}
|
||||
|
||||
fn move_position(&mut self, p: Point) {
|
||||
self.position = p;
|
||||
}
|
||||
|
||||
fn process(&mut self, message: Message) {
|
||||
// TODO: create a match expression to process the different message variants
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_match_message_call() {
|
||||
let mut state = State {
|
||||
quit: false,
|
||||
position: Point { x: 0, y: 0 },
|
||||
color: (0, 0, 0),
|
||||
};
|
||||
state.process(Message::ChangeColor((255, 0, 255)));
|
||||
state.process(Message::Echo(String::from("hello world")));
|
||||
state.process(Message::Move(Point { x: 10, y: 15 }));
|
||||
state.process(Message::Quit);
|
||||
|
||||
assert_eq!(state.color, (255, 0, 255));
|
||||
assert_eq!(state.position.x, 10);
|
||||
assert_eq!(state.position.y, 15);
|
||||
assert_eq!(state.quit, true);
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
# Error handling
|
||||
Most errors aren’t serious enough to require the program to stop entirely.
|
||||
Sometimes, when a function fails, it’s for a reason that you can easily interpret and respond to.
|
||||
For example, if you try to open a file and that operation fails because the file doesn’t exist, you might want to create the file instead of terminating the process.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)
|
||||
- [Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html)
|
||||
- [Result](https://doc.rust-lang.org/rust-by-example/error/result.html)
|
||||
- [Boxing errors](https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/boxing_errors.html)
|
|
@ -1,31 +0,0 @@
|
|||
// errors3.rs
|
||||
// This is a program that is trying to use a completed version of the
|
||||
// `total_cost` function from the previous exercise. It's not working though!
|
||||
// Why not? What should we do to fix it?
|
||||
// Execute `rustlings hint errors3` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::num::ParseIntError;
|
||||
|
||||
fn main() {
|
||||
let mut tokens = 100;
|
||||
let pretend_user_input = "8";
|
||||
|
||||
let cost = total_cost(pretend_user_input)?;
|
||||
|
||||
if cost > tokens {
|
||||
println!("You can't afford that many!");
|
||||
} else {
|
||||
tokens -= cost;
|
||||
println!("You now have {} tokens.", tokens);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
|
||||
let processing_fee = 1;
|
||||
let cost_per_item = 5;
|
||||
let qty = item_quantity.parse::<i32>()?;
|
||||
|
||||
Ok(qty * cost_per_item + processing_fee)
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
// errors4.rs
|
||||
// Make this test pass! Execute `rustlings hint errors4` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct PositiveNonzeroInteger(u64);
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum CreationError {
|
||||
Negative,
|
||||
Zero,
|
||||
}
|
||||
|
||||
impl PositiveNonzeroInteger {
|
||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
||||
Ok(PositiveNonzeroInteger(value as u64))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_creation() {
|
||||
assert!(PositiveNonzeroInteger::new(10).is_ok());
|
||||
assert_eq!(
|
||||
Err(CreationError::Negative),
|
||||
PositiveNonzeroInteger::new(-10)
|
||||
);
|
||||
assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0));
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
// errors5.rs
|
||||
|
||||
// This program uses a completed version of the code from errors4.
|
||||
// It won't compile right now! Why?
|
||||
// Execute `rustlings hint errors5` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::num::ParseIntError;
|
||||
|
||||
// TODO: update the return type of `main()` to make this compile.
|
||||
fn main() -> Result<(), ParseIntError> {
|
||||
let pretend_user_input = "42";
|
||||
let x: i64 = pretend_user_input.parse()?;
|
||||
println!("output={:?}", PositiveNonzeroInteger::new(x)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Don't change anything below this line.
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct PositiveNonzeroInteger(u64);
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum CreationError {
|
||||
Negative,
|
||||
Zero,
|
||||
}
|
||||
|
||||
impl PositiveNonzeroInteger {
|
||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
||||
match value {
|
||||
x if x < 0 => Err(CreationError::Negative),
|
||||
x if x == 0 => Err(CreationError::Zero),
|
||||
x => Ok(PositiveNonzeroInteger(x as u64))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is required so that `CreationError` can implement `error::Error`.
|
||||
impl fmt::Display for CreationError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let description = match *self {
|
||||
CreationError::Negative => "number is negative",
|
||||
CreationError::Zero => "number is zero",
|
||||
};
|
||||
f.write_str(description)
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for CreationError {}
|
|
@ -1,95 +0,0 @@
|
|||
// errors6.rs
|
||||
|
||||
// Using catch-all error types like `Box<dyn error::Error>` isn't recommended
|
||||
// for library code, where callers might want to make decisions based on the
|
||||
// error content, instead of printing it out or propagating it further. Here,
|
||||
// we define a custom error type to make it possible for callers to decide
|
||||
// what to do next when our function returns an error.
|
||||
|
||||
// Make these tests pass! Execute `rustlings hint errors6` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::num::ParseIntError;
|
||||
|
||||
// This is a custom error type that we will be using in `parse_pos_nonzero()`.
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum ParsePosNonzeroError {
|
||||
Creation(CreationError),
|
||||
ParseInt(ParseIntError)
|
||||
}
|
||||
|
||||
impl ParsePosNonzeroError {
|
||||
fn from_creation(err: CreationError) -> ParsePosNonzeroError {
|
||||
ParsePosNonzeroError::Creation(err)
|
||||
}
|
||||
// TODO: add another error conversion function here.
|
||||
}
|
||||
|
||||
fn parse_pos_nonzero(s: &str)
|
||||
-> Result<PositiveNonzeroInteger, ParsePosNonzeroError>
|
||||
{
|
||||
// TODO: change this to return an appropriate error instead of panicking
|
||||
// when `parse()` returns an error.
|
||||
let x: i64 = s.parse().unwrap();
|
||||
PositiveNonzeroInteger::new(x)
|
||||
.map_err(ParsePosNonzeroError::from_creation)
|
||||
}
|
||||
|
||||
// Don't change anything below this line.
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct PositiveNonzeroInteger(u64);
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum CreationError {
|
||||
Negative,
|
||||
Zero,
|
||||
}
|
||||
|
||||
impl PositiveNonzeroInteger {
|
||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
||||
match value {
|
||||
x if x < 0 => Err(CreationError::Negative),
|
||||
x if x == 0 => Err(CreationError::Zero),
|
||||
x => Ok(PositiveNonzeroInteger(x as u64))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_error() {
|
||||
// We can't construct a ParseIntError, so we have to pattern match.
|
||||
assert!(matches!(
|
||||
parse_pos_nonzero("not a number"),
|
||||
Err(ParsePosNonzeroError::ParseInt(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative() {
|
||||
assert_eq!(
|
||||
parse_pos_nonzero("-555"),
|
||||
Err(ParsePosNonzeroError::Creation(CreationError::Negative))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero() {
|
||||
assert_eq!(
|
||||
parse_pos_nonzero("0"),
|
||||
Err(ParsePosNonzeroError::Creation(CreationError::Zero))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_positive() {
|
||||
let x = PositiveNonzeroInteger::new(42);
|
||||
assert!(x.is_ok());
|
||||
assert_eq!(parse_pos_nonzero("42"), Ok(x.unwrap()));
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
# Functions
|
||||
|
||||
Here, you'll learn how to write functions and how Rust's compiler can trace things way back.
|
||||
|
||||
## Further information
|
||||
|
||||
- [How Functions Work](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html)
|
|
@ -1,8 +0,0 @@
|
|||
// functions1.rs
|
||||
// Make me compile! Execute `rustlings hint functions1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
call_me();
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// functions2.rs
|
||||
// Make me compile! Execute `rustlings hint functions2` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
call_me(3);
|
||||
}
|
||||
|
||||
fn call_me(num:) {
|
||||
for i in 0..num {
|
||||
println!("Ring! Call number {}", i + 1);
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// functions3.rs
|
||||
// Make me compile! Execute `rustlings hint functions3` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
call_me();
|
||||
}
|
||||
|
||||
fn call_me(num: u32) {
|
||||
for i in 0..num {
|
||||
println!("Ring! Call number {}", i + 1);
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
// functions5.rs
|
||||
// Make me compile! Execute `rustlings hint functions5` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let answer = square(3);
|
||||
println!("The answer is {}", answer);
|
||||
}
|
||||
|
||||
fn square(num: i32) -> i32 {
|
||||
num * num;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
# Generics
|
||||
|
||||
Generics is the topic of generalizing types and functionalities to broader cases.
|
||||
This is extremely useful for reducing code duplication in many ways, but can call for rather involving syntax.
|
||||
Namely, being generic requires taking great care to specify over which types a generic type is actually considered valid.
|
||||
The simplest and most common use of generics is for type parameters.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Generic Data Types](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html)
|
||||
- [Bounds](https://doc.rust-lang.org/rust-by-example/generics/bounds.html)
|
|
@ -1,11 +0,0 @@
|
|||
// This shopping list program isn't compiling!
|
||||
// Use your knowledge of generics to fix it.
|
||||
|
||||
// Execute `rustlings hint generics1` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let mut shopping_list: Vec<?> = Vec::new();
|
||||
shopping_list.push("milk");
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
// This powerful wrapper provides the ability to store a positive integer value.
|
||||
// Rewrite it using generics so that it supports wrapping ANY type.
|
||||
|
||||
// Execute `rustlings hint generics2` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
struct Wrapper {
|
||||
value: u32,
|
||||
}
|
||||
|
||||
impl Wrapper {
|
||||
pub fn new(value: u32) -> Self {
|
||||
Wrapper { value }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn store_u32_in_wrapper() {
|
||||
assert_eq!(Wrapper::new(42).value, 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn store_str_in_wrapper() {
|
||||
assert_eq!(Wrapper::new("Foo").value, "Foo");
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
// An imaginary magical school has a new report card generation system written in Rust!
|
||||
// Currently the system only supports creating report cards where the student's grade
|
||||
// is represented numerically (e.g. 1.0 -> 5.5).
|
||||
// However, the school also issues alphabetical grades (A+ -> F-) and needs
|
||||
// to be able to print both types of report card!
|
||||
|
||||
// Make the necessary code changes in the struct ReportCard and the impl block
|
||||
// to support alphabetical report cards. Change the Grade in the second test to "A+"
|
||||
// to show that your changes allow alphabetical grades.
|
||||
|
||||
// Execute 'rustlings hint generics3' for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
pub struct ReportCard {
|
||||
pub grade: f32,
|
||||
pub student_name: String,
|
||||
pub student_age: u8,
|
||||
}
|
||||
|
||||
impl ReportCard {
|
||||
pub fn print(&self) -> String {
|
||||
format!("{} ({}) - achieved a grade of {}",
|
||||
&self.student_name, &self.student_age, &self.grade)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn generate_numeric_report_card() {
|
||||
let report_card = ReportCard {
|
||||
grade: 2.1,
|
||||
student_name: "Tom Wriggle".to_string(),
|
||||
student_age: 12,
|
||||
};
|
||||
assert_eq!(
|
||||
report_card.print(),
|
||||
"Tom Wriggle (12) - achieved a grade of 2.1"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_alphabetic_report_card() {
|
||||
// TODO: Make sure to change the grade here after you finish the exercise.
|
||||
let report_card = ReportCard {
|
||||
grade: 2.1,
|
||||
student_name: "Gary Plotter".to_string(),
|
||||
student_age: 11,
|
||||
};
|
||||
assert_eq!(
|
||||
report_card.print(),
|
||||
"Gary Plotter (11) - achieved a grade of A+"
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
# If
|
||||
|
||||
`if`, the most basic type of control flow, is what you'll learn here.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Control Flow - if expressions](https://doc.rust-lang.org/book/ch03-05-control-flow.html#if-expressions)
|
|
@ -1,27 +0,0 @@
|
|||
// if1.rs
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
pub fn bigger(a: i32, b: i32) -> i32 {
|
||||
// Complete this function to return the bigger number!
|
||||
// Do not use:
|
||||
// - another function call
|
||||
// - additional variables
|
||||
// Execute `rustlings hint if1` for hints
|
||||
}
|
||||
|
||||
// Don't mind this for now :)
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn ten_is_bigger_than_eight() {
|
||||
assert_eq!(10, bigger(10, 8));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fortytwo_is_bigger_than_thirtytwo() {
|
||||
assert_eq!(42, bigger(32, 42));
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
// if2.rs
|
||||
|
||||
// Step 1: Make me compile!
|
||||
// Step 2: Get the bar_for_fuzz and default_to_baz tests passing!
|
||||
// Execute the command `rustlings hint if2` if you want a hint :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
pub fn fizz_if_foo(fizzish: &str) -> &str {
|
||||
if fizzish == "fizz" {
|
||||
"foo"
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
// No test changes needed!
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn foo_for_fizz() {
|
||||
assert_eq!(fizz_if_foo("fizz"), "foo")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bar_for_fuzz() {
|
||||
assert_eq!(fizz_if_foo("fuzz"), "bar")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_to_baz() {
|
||||
assert_eq!(fizz_if_foo("literally anything"), "baz")
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
# Macros
|
||||
|
||||
Rust's macro system is very powerful, but also kind of difficult to wrap your
|
||||
head around. We're not going to teach you how to write your own fully-featured
|
||||
macros. Instead, we'll show you how to use and create them.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html)
|
||||
- [The Little Book of Rust Macros](https://danielkeep.github.io/tlborm/book/index.html)
|
|
@ -1,14 +0,0 @@
|
|||
// macros1.rs
|
||||
// Make me compile! Execute `rustlings hint macros1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
macro_rules! my_macro {
|
||||
() => {
|
||||
println!("Check out my macro!");
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
my_macro();
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// macros2.rs
|
||||
// Make me compile! Execute `rustlings hint macros2` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
my_macro!();
|
||||
}
|
||||
|
||||
macro_rules! my_macro {
|
||||
() => {
|
||||
println!("Check out my macro!");
|
||||
};
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
// macros3.rs
|
||||
// Make me compile, without taking the macro out of the module!
|
||||
// Execute `rustlings hint macros3` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
mod macros {
|
||||
macro_rules! my_macro {
|
||||
() => {
|
||||
println!("Check out my macro!");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
my_macro!();
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
// macros4.rs
|
||||
// Make me compile! Execute `rustlings hint macros4` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
macro_rules! my_macro {
|
||||
() => {
|
||||
println!("Check out my macro!");
|
||||
}
|
||||
($val:expr) => {
|
||||
println!("Look at this other macro: {}", $val);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
my_macro!();
|
||||
my_macro!(7777);
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
# Modules
|
||||
|
||||
In this section we'll give you an introduction to Rust's module system.
|
||||
|
||||
## Further information
|
||||
|
||||
- [The Module System](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html)
|
|
@ -1,20 +0,0 @@
|
|||
// modules1.rs
|
||||
// Make me compile! Execute `rustlings hint modules1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
mod sausage_factory {
|
||||
// Don't let anybody outside of this module see this!
|
||||
fn get_secret_recipe() -> String {
|
||||
String::from("Ginger")
|
||||
}
|
||||
|
||||
fn make_sausage() {
|
||||
get_secret_recipe();
|
||||
println!("sausage!");
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
sausage_factory::make_sausage();
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
// modules2.rs
|
||||
// You can bring module paths into scopes and provide new names for them with the
|
||||
// 'use' and 'as' keywords. Fix these 'use' statements to make the code compile.
|
||||
// Make me compile! Execute `rustlings hint modules2` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
mod delicious_snacks {
|
||||
|
||||
// TODO: Fix these use statements
|
||||
use self::fruits::PEAR as ???
|
||||
use self::veggies::CUCUMBER as ???
|
||||
|
||||
mod fruits {
|
||||
pub const PEAR: &'static str = "Pear";
|
||||
pub const APPLE: &'static str = "Apple";
|
||||
}
|
||||
|
||||
mod veggies {
|
||||
pub const CUCUMBER: &'static str = "Cucumber";
|
||||
pub const CARROT: &'static str = "Carrot";
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!(
|
||||
"favorite snacks: {} and {}",
|
||||
delicious_snacks::fruit,
|
||||
delicious_snacks::veggie
|
||||
);
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
// modules3.rs
|
||||
// You can use the 'use' keyword to bring module paths from modules from anywhere
|
||||
// and especially from the Rust standard library into your scope.
|
||||
// Bring SystemTime and UNIX_EPOCH
|
||||
// from the std::time module. Bonus style points if you can do it with one line!
|
||||
// Make me compile! Execute `rustlings hint modules3` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// TODO: Complete this use statement
|
||||
use ???
|
||||
|
||||
fn main() {
|
||||
match SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||
Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
|
||||
Err(_) => panic!("SystemTime before UNIX EPOCH!"),
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
# Move Semantics
|
||||
|
||||
These exercises are adapted from [pnkfelix](https://github.com/pnkfelix)'s [Rust Tutorial](https://pnkfelix.github.io/rust-examples-icfp2014/) -- Thank you Felix!!!
|
||||
|
||||
## Further information
|
||||
|
||||
For this section, the book links are especially important.
|
||||
|
||||
- [Ownership](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html)
|
||||
- [Reference and borrowing](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html)
|
|
@ -1,28 +0,0 @@
|
|||
// move_semantics2.rs
|
||||
// Make me compile without changing line 13!
|
||||
// Execute `rustlings hint move_semantics2` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let vec0 = Vec::new();
|
||||
|
||||
let mut vec1 = fill_vec(vec0);
|
||||
|
||||
// Do not change the following line!
|
||||
println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0);
|
||||
|
||||
vec1.push(88);
|
||||
|
||||
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
|
||||
}
|
||||
|
||||
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
|
||||
let mut vec = vec;
|
||||
|
||||
vec.push(22);
|
||||
vec.push(44);
|
||||
vec.push(66);
|
||||
|
||||
vec
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
// move_semantics4.rs
|
||||
// Refactor this code so that instead of having `vec0` and creating the vector
|
||||
// in `fn main`, we create it within `fn fill_vec` and transfer the
|
||||
// freshly created vector from fill_vec to its caller.
|
||||
// Execute `rustlings hint move_semantics4` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let vec0 = Vec::new();
|
||||
|
||||
let mut vec1 = fill_vec(vec0);
|
||||
|
||||
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
|
||||
|
||||
vec1.push(88);
|
||||
|
||||
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
|
||||
}
|
||||
|
||||
// `fill_vec()` no longer takes `vec: Vec<i32>` as argument
|
||||
fn fill_vec() -> Vec<i32> {
|
||||
let mut vec = vec;
|
||||
|
||||
vec.push(22);
|
||||
vec.push(44);
|
||||
vec.push(66);
|
||||
|
||||
vec
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
// move_semantics5.rs
|
||||
// Make me compile only by reordering the lines in `main()`, but without
|
||||
// adding, changing or removing any of them.
|
||||
// Execute `rustlings hint move_semantics5` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let mut x = 100;
|
||||
let y = &mut x;
|
||||
let z = &mut x;
|
||||
*y += 100;
|
||||
*z += 1000;
|
||||
assert_eq!(x, 1200);
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
# Option
|
||||
|
||||
Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not.
|
||||
Option types are very common in Rust code, as they have a number of uses:
|
||||
- Initial values
|
||||
- Return values for functions that are not defined over their entire input range (partial functions)
|
||||
- Return value for otherwise reporting simple errors, where None is returned on error
|
||||
- Optional struct fields
|
||||
- Struct fields that can be loaned or "taken"
|
||||
- Optional function arguments
|
||||
- Nullable pointers
|
||||
- Swapping things out of difficult situations
|
||||
|
||||
## Further Information
|
||||
|
||||
- [Option Enum Format](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-enum-definitions)
|
||||
- [Option Module Documentation](https://doc.rust-lang.org/std/option/)
|
||||
- [Option Enum Documentation](https://doc.rust-lang.org/std/option/enum.Option.html)
|
|
@ -1,23 +0,0 @@
|
|||
// option1.rs
|
||||
// Make me compile! Execute `rustlings hint option1` for hints
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// you can modify anything EXCEPT for this function's sig
|
||||
fn print_number(maybe_number: Option<u16>) {
|
||||
println!("printing: {}", maybe_number.unwrap());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
print_number(13);
|
||||
print_number(99);
|
||||
|
||||
let mut numbers: [Option<u16>; 5];
|
||||
for iter in 0..5 {
|
||||
let number_to_add: u16 = {
|
||||
((iter * 1235) + 2) / (4 * 16)
|
||||
};
|
||||
|
||||
numbers[iter as usize] = number_to_add;
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// option2.rs
|
||||
// Make me compile! Execute `rustlings hint option2` for hints
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let optional_word = Some(String::from("rustlings"));
|
||||
// TODO: Make this an if let statement whose value is "Some" type
|
||||
word = optional_word {
|
||||
println!("The word is: {}", word);
|
||||
} else {
|
||||
println!("The optional word doesn't contain anything");
|
||||
}
|
||||
|
||||
let mut optional_integers_vec: Vec<Option<i8>> = Vec::new();
|
||||
for x in 1..10 {
|
||||
optional_integers_vec.push(Some(x));
|
||||
}
|
||||
|
||||
// TODO: make this a while let statement - remember that vector.pop also adds another layer of Option<T>
|
||||
// You can stack `Option<T>`'s into while let and if let
|
||||
integer = optional_integers_vec.pop() {
|
||||
println!("current value: {}", integer);
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
// option3.rs
|
||||
// Make me compile! Execute `rustlings hint option3` for hints
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let y: Option<Point> = Some(Point { x: 100, y: 200 });
|
||||
|
||||
match y {
|
||||
Some(p) => println!("Co-ordinates are {},{} ", p.x, p.y),
|
||||
_ => println!("no match"),
|
||||
}
|
||||
y; // Fix without deleting this line.
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
# Primitive Types
|
||||
|
||||
Rust has a couple of basic types that are directly implemented into the
|
||||
compiler. In this section, we'll go through the most important ones.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Data Types](https://doc.rust-lang.org/stable/book/ch03-02-data-types.html)
|
||||
- [The Slice Type](https://doc.rust-lang.org/stable/book/ch04-03-slices.html)
|
|
@ -1,15 +0,0 @@
|
|||
// primitive_types3.rs
|
||||
// Create an array with at least 100 elements in it where the ??? is.
|
||||
// Execute `rustlings hint primitive_types3` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let a = ???
|
||||
|
||||
if a.len() >= 100 {
|
||||
println!("Wow, that's a big array!");
|
||||
} else {
|
||||
println!("Meh, I eat arrays like that for breakfast.");
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// primitive_types4.rs
|
||||
// Get a slice out of Array a where the ??? is so that the test passes.
|
||||
// Execute `rustlings hint primitive_types4` for hints!!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[test]
|
||||
fn slice_out_of_array() {
|
||||
let a = [1, 2, 3, 4, 5];
|
||||
|
||||
let nice_slice = ???
|
||||
|
||||
assert_eq!([2, 3, 4], nice_slice)
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
// primitive_types5.rs
|
||||
// Destructure the `cat` tuple so that the println will work.
|
||||
// Execute `rustlings hint primitive_types5` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let cat = ("Furry McFurson", 3.5);
|
||||
let /* your pattern here */ = cat;
|
||||
|
||||
println!("{} is {} years old.", name, age);
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
// primitive_types6.rs
|
||||
// Use a tuple index to access the second element of `numbers`.
|
||||
// You can put the expression for the second element where ??? is so that the test passes.
|
||||
// Execute `rustlings hint primitive_types6` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[test]
|
||||
fn indexing_tuple() {
|
||||
let numbers = (1, 2, 3);
|
||||
// Replace below ??? with the tuple indexing syntax.
|
||||
let second = ???;
|
||||
|
||||
assert_eq!(2, second,
|
||||
"This is not the 2nd number in the tuple!")
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// quiz1.rs
|
||||
// This is a quiz for the following sections:
|
||||
// - Variables
|
||||
// - Functions
|
||||
|
||||
// Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy
|
||||
// more than 40 at once, each apple only costs 1! Write a function that calculates
|
||||
// the price of an order of apples given the quantity bought. No hints this time!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// Put your function here!
|
||||
// fn calculate_apple_price {
|
||||
|
||||
// Don't modify this function!
|
||||
#[test]
|
||||
fn verify_test() {
|
||||
let price1 = calculate_apple_price(35);
|
||||
let price2 = calculate_apple_price(40);
|
||||
let price3 = calculate_apple_price(65);
|
||||
|
||||
assert_eq!(70, price1);
|
||||
assert_eq!(80, price2);
|
||||
assert_eq!(65, price3);
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
// quiz2.rs
|
||||
// This is a quiz for the following sections:
|
||||
// - Strings
|
||||
|
||||
// Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your
|
||||
// task is to call one of these two functions on each value depending on what
|
||||
// you think each value is. That is, add either `string_slice` or `string`
|
||||
// before the parentheses on each line. If you're right, it will compile!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn string_slice(arg: &str) {
|
||||
println!("{}", arg);
|
||||
}
|
||||
fn string(arg: String) {
|
||||
println!("{}", arg);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
???("blue");
|
||||
???("red".to_string());
|
||||
???(String::from("hi"));
|
||||
???("rust is fun!".to_owned());
|
||||
???("nice weather".into());
|
||||
???(format!("Interpolation {}", "Station"));
|
||||
???(&String::from("abc")[0..1]);
|
||||
???(" hello there ".trim());
|
||||
???("Happy Monday!".to_string().replace("Mon", "Tues"));
|
||||
???("mY sHiFt KeY iS sTiCkY".to_lowercase());
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
// quiz3.rs
|
||||
// This is a quiz for the following sections:
|
||||
// - Tests
|
||||
|
||||
// This quiz isn't testing our function -- make it do that in such a way that
|
||||
// the test passes. Then write a second test that tests that we get the result
|
||||
// we expect to get when we call `times_two` with a negative number.
|
||||
// No hints, you can do this :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
pub fn times_two(num: i32) -> i32 {
|
||||
num * 2
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn returns_twice_of_positive_numbers() {
|
||||
assert_eq!(times_two(4), ???);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_twice_of_negative_numbers() {
|
||||
// TODO replace unimplemented!() with an assert for `times_two(-4)`
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
// quiz4.rs
|
||||
// This quiz covers the sections:
|
||||
// - Modules
|
||||
// - Macros
|
||||
|
||||
// Write a macro that passes the quiz! No hints this time, you can do it!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_my_macro_world() {
|
||||
assert_eq!(my_macro!("world!"), "Hello world!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_my_macro_goodbye() {
|
||||
assert_eq!(my_macro!("goodbye!"), "Hello goodbye!");
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
# Standard library types
|
||||
|
||||
This section will teach you about Box, Shared-State Concurrency and Iterators.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html)
|
||||
- [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html)
|
||||
- [Iterator](https://doc.rust-lang.org/book/ch13-02-iterators.html)
|
||||
- [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/)
|
|
@ -1,47 +0,0 @@
|
|||
// arc1.rs
|
||||
// In this exercise, we are given a Vec of u32 called "numbers" with values ranging
|
||||
// from 0 to 99 -- [ 0, 1, 2, ..., 98, 99 ]
|
||||
// We would like to use this set of numbers within 8 different threads simultaneously.
|
||||
// Each thread is going to get the sum of every eighth value, with an offset.
|
||||
// The first thread (offset 0), will sum 0, 8, 16, ...
|
||||
// The second thread (offset 1), will sum 1, 9, 17, ...
|
||||
// The third thread (offset 2), will sum 2, 10, 18, ...
|
||||
// ...
|
||||
// The eighth thread (offset 7), will sum 7, 15, 23, ...
|
||||
|
||||
// Because we are using threads, our values need to be thread-safe. Therefore,
|
||||
// we are using Arc. We need to make a change in each of the two TODOs.
|
||||
|
||||
|
||||
// Make this code compile by filling in a value for `shared_numbers` where the
|
||||
// first TODO comment is, and create an initial binding for `child_numbers`
|
||||
// where the second TODO comment is. Try not to create any copies of the `numbers` Vec!
|
||||
// Execute `rustlings hint arc1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#![forbid(unused_imports)] // Do not change this, (or the next) line.
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
let numbers: Vec<_> = (0..100u32).collect();
|
||||
let shared_numbers = // TODO
|
||||
let mut joinhandles = Vec::new();
|
||||
|
||||
for offset in 0..8 {
|
||||
let child_numbers = // TODO
|
||||
joinhandles.push(thread::spawn(move || {
|
||||
let mut i = offset;
|
||||
let mut sum = 0;
|
||||
while i < child_numbers.len() {
|
||||
sum += child_numbers[i];
|
||||
i += 8;
|
||||
}
|
||||
println!("Sum of offset {} is {}", offset, sum);
|
||||
}));
|
||||
}
|
||||
for handle in joinhandles.into_iter() {
|
||||
handle.join().unwrap();
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
// box1.rs
|
||||
//
|
||||
// At compile time, Rust needs to know how much space a type takes up. This becomes problematic
|
||||
// for recursive types, where a value can have as part of itself another value of the same type.
|
||||
// To get around the issue, we can use a `Box` - a smart pointer used to store data on the heap,
|
||||
// which also allows us to wrap a recursive type.
|
||||
//
|
||||
// The recursive type we're implementing in this exercise is the `cons list` - a data structure
|
||||
// frequently found in functional programming languages. Each item in a cons list contains two
|
||||
// elements: the value of the current item and the next item. The last item is a value called `Nil`.
|
||||
//
|
||||
// Step 1: use a `Box` in the enum definition to make the code compile
|
||||
// Step 2: create both empty and non-empty cons lists by replacing `unimplemented!()`
|
||||
//
|
||||
// Note: the tests should not be changed
|
||||
//
|
||||
// Execute `rustlings hint box1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum List {
|
||||
Cons(i32, List),
|
||||
Nil,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("This is an empty cons list: {:?}", create_empty_list());
|
||||
println!(
|
||||
"This is a non-empty cons list: {:?}",
|
||||
create_non_empty_list()
|
||||
);
|
||||
}
|
||||
|
||||
pub fn create_empty_list() -> List {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn create_non_empty_list() -> List {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_create_empty_list() {
|
||||
assert_eq!(List::Nil, create_empty_list())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_non_empty_list() {
|
||||
assert_ne!(create_empty_list(), create_non_empty_list())
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
// iterators1.rs
|
||||
//
|
||||
// Make me compile by filling in the `???`s
|
||||
//
|
||||
// When performing operations on elements within a collection, iterators are essential.
|
||||
// This module helps you get familiar with the structure of using an iterator and
|
||||
// how to go through elements within an iterable collection.
|
||||
//
|
||||
// Execute `rustlings hint iterators1` for hints :D
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main () {
|
||||
let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"];
|
||||
|
||||
let mut my_iterable_fav_fruits = ???; // TODO: Step 1
|
||||
|
||||
assert_eq!(my_iterable_fav_fruits.next(), Some(&"banana"));
|
||||
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2
|
||||
assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado"));
|
||||
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2.1
|
||||
assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry"));
|
||||
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 3
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
// iterators2.rs
|
||||
// In this exercise, you'll learn some of the unique advantages that iterators
|
||||
// can offer. Follow the steps to complete the exercise.
|
||||
// As always, there are hints if you execute `rustlings hint iterators2`!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// Step 1.
|
||||
// Complete the `capitalize_first` function.
|
||||
// "hello" -> "Hello"
|
||||
pub fn capitalize_first(input: &str) -> String {
|
||||
let mut c = input.chars();
|
||||
match c.next() {
|
||||
None => String::new(),
|
||||
Some(first) => ???,
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2.
|
||||
// Apply the `capitalize_first` function to a slice of string slices.
|
||||
// Return a vector of strings.
|
||||
// ["hello", "world"] -> ["Hello", "World"]
|
||||
pub fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
// Step 3.
|
||||
// Apply the `capitalize_first` function again to a slice of string slices.
|
||||
// Return a single string.
|
||||
// ["hello", " ", "world"] -> "Hello World"
|
||||
pub fn capitalize_words_string(words: &[&str]) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_success() {
|
||||
assert_eq!(capitalize_first("hello"), "Hello");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty() {
|
||||
assert_eq!(capitalize_first(""), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterate_string_vec() {
|
||||
let words = vec!["hello", "world"];
|
||||
assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterate_into_string() {
|
||||
let words = vec!["hello", " ", "world"];
|
||||
assert_eq!(capitalize_words_string(&words), "Hello World");
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
// iterators3.rs
|
||||
// This is a bigger exercise than most of the others! You can do it!
|
||||
// Here is your mission, should you choose to accept it:
|
||||
// 1. Complete the divide function to get the first four tests to pass.
|
||||
// 2. Get the remaining tests to pass by completing the result_with_list and
|
||||
// list_of_results functions.
|
||||
// Execute `rustlings hint iterators3` to get some hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum DivisionError {
|
||||
NotDivisible(NotDivisibleError),
|
||||
DivideByZero,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct NotDivisibleError {
|
||||
dividend: i32,
|
||||
divisor: i32,
|
||||
}
|
||||
|
||||
// Calculate `a` divided by `b` if `a` is evenly divisible by `b`.
|
||||
// Otherwise, return a suitable error.
|
||||
pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {}
|
||||
|
||||
// Complete the function and return a value of the correct type so the test passes.
|
||||
// Desired output: Ok([1, 11, 1426, 3])
|
||||
fn result_with_list() -> () {
|
||||
let numbers = vec![27, 297, 38502, 81];
|
||||
let division_results = numbers.into_iter().map(|n| divide(n, 27));
|
||||
}
|
||||
|
||||
// Complete the function and return a value of the correct type so the test passes.
|
||||
// Desired output: [Ok(1), Ok(11), Ok(1426), Ok(3)]
|
||||
fn list_of_results() -> () {
|
||||
let numbers = vec![27, 297, 38502, 81];
|
||||
let division_results = numbers.into_iter().map(|n| divide(n, 27));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_success() {
|
||||
assert_eq!(divide(81, 9), Ok(9));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_divisible() {
|
||||
assert_eq!(
|
||||
divide(81, 6),
|
||||
Err(DivisionError::NotDivisible(NotDivisibleError {
|
||||
dividend: 81,
|
||||
divisor: 6
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_divide_by_0() {
|
||||
assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_divide_0_by_something() {
|
||||
assert_eq!(divide(0, 81), Ok(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_result_with_list() {
|
||||
assert_eq!(format!("{:?}", result_with_list()), "Ok([1, 11, 1426, 3])");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_of_results() {
|
||||
assert_eq!(
|
||||
format!("{:?}", list_of_results()),
|
||||
"[Ok(1), Ok(11), Ok(1426), Ok(3)]"
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
// iterators5.rs
|
||||
// Let's define a simple model to track Rustlings exercise progress. Progress
|
||||
// will be modelled using a hash map. The name of the exercise is the key and
|
||||
// the progress is the value. Two counting functions were created to count the
|
||||
// number of exercises with a given progress. These counting functions use
|
||||
// imperative style for loops. Recreate this counting functionality using
|
||||
// iterators. Only the two iterator methods (count_iterator and
|
||||
// count_collection_iterator) need to be modified.
|
||||
// Execute `rustlings hint iterators5` for hints.
|
||||
//
|
||||
// Make the code compile and the tests pass.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum Progress {
|
||||
None,
|
||||
Some,
|
||||
Complete,
|
||||
}
|
||||
|
||||
fn count_for(map: &HashMap<String, Progress>, value: Progress) -> usize {
|
||||
let mut count = 0;
|
||||
for val in map.values() {
|
||||
if val == &value {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
fn count_iterator(map: &HashMap<String, Progress>, value: Progress) -> usize {
|
||||
// map is a hashmap with String keys and Progress values.
|
||||
// map = { "variables1": Complete, "from_str": None, ... }
|
||||
}
|
||||
|
||||
fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
|
||||
let mut count = 0;
|
||||
for map in collection {
|
||||
for val in map.values() {
|
||||
if val == &value {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
|
||||
// collection is a slice of hashmaps.
|
||||
// collection = [{ "variables1": Complete, "from_str": None, ... },
|
||||
// { "variables2": Complete, ... }, ... ]
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn count_complete() {
|
||||
let map = get_map();
|
||||
assert_eq!(3, count_iterator(&map, Progress::Complete));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn count_equals_for() {
|
||||
let map = get_map();
|
||||
assert_eq!(
|
||||
count_for(&map, Progress::Complete),
|
||||
count_iterator(&map, Progress::Complete)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn count_collection_complete() {
|
||||
let collection = get_vec_map();
|
||||
assert_eq!(
|
||||
6,
|
||||
count_collection_iterator(&collection, Progress::Complete)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn count_collection_equals_for() {
|
||||
let collection = get_vec_map();
|
||||
assert_eq!(
|
||||
count_collection_for(&collection, Progress::Complete),
|
||||
count_collection_iterator(&collection, Progress::Complete)
|
||||
);
|
||||
}
|
||||
|
||||
fn get_map() -> HashMap<String, Progress> {
|
||||
use Progress::*;
|
||||
|
||||
let mut map = HashMap::new();
|
||||
map.insert(String::from("variables1"), Complete);
|
||||
map.insert(String::from("functions1"), Complete);
|
||||
map.insert(String::from("hashmap1"), Complete);
|
||||
map.insert(String::from("arc1"), Some);
|
||||
map.insert(String::from("as_ref_mut"), None);
|
||||
map.insert(String::from("from_str"), None);
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
fn get_vec_map() -> Vec<HashMap<String, Progress>> {
|
||||
use Progress::*;
|
||||
|
||||
let map = get_map();
|
||||
|
||||
let mut other = HashMap::new();
|
||||
other.insert(String::from("variables2"), Complete);
|
||||
other.insert(String::from("functions2"), Complete);
|
||||
other.insert(String::from("if1"), Complete);
|
||||
other.insert(String::from("from_into"), None);
|
||||
other.insert(String::from("try_from_into"), None);
|
||||
|
||||
vec![map, other]
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
# Strings
|
||||
|
||||
Rust has two string types, a string slice (`&str`) and an owned string (`String`).
|
||||
We're not going to dictate when you should use which one, but we'll show you how
|
||||
to identify and create them, as well as use them.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Strings](https://doc.rust-lang.org/book/ch08-02-strings.html)
|
|
@ -1,14 +0,0 @@
|
|||
// strings1.rs
|
||||
// Make me compile without changing the function signature!
|
||||
// Execute `rustlings hint strings1` for hints ;)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let answer = current_favorite_color();
|
||||
println!("My current favorite color is {}", answer);
|
||||
}
|
||||
|
||||
fn current_favorite_color() -> String {
|
||||
"blue"
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
# Structs
|
||||
|
||||
Rust has three struct types: a classic C struct, a tuple struct, and a unit struct.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Structures](https://doc.rust-lang.org/book/ch05-01-defining-structs.html)
|
||||
- [Method Syntax](https://doc.rust-lang.org/book/ch05-03-method-syntax.html)
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue