mirror of
https://github.com/rust-lang/rustlings.git
synced 2026-01-11 21:29:18 +00:00
Merge branch 'main' of github.com:rust-lang/rustlings into rust-lang-main
This commit is contained in:
commit
0152f6dcd4
@ -1227,6 +1227,231 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"content"
|
"content"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "jackos",
|
||||||
|
"name": "Jack Clayton",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/77730378?v=4",
|
||||||
|
"profile": "http://rustnote.com",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "klkl0808",
|
||||||
|
"name": "Konstantin",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/24694249?v=4",
|
||||||
|
"profile": "https://github.com/klkl0808",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "0pling",
|
||||||
|
"name": "0pling",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/104090344?v=4",
|
||||||
|
"profile": "https://github.com/0pling",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "KatanaFluorescent",
|
||||||
|
"name": "KatanaFluorescent",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/60199077?v=4",
|
||||||
|
"profile": "https://github.com/KatanaFluorescent",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Drew-Morris",
|
||||||
|
"name": "Drew Morris",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/95818166?v=4",
|
||||||
|
"profile": "https://github.com/Drew-Morris",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "camperdue42",
|
||||||
|
"name": "camperdue42",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/43047763?v=4",
|
||||||
|
"profile": "https://github.com/camperdue42",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "YsuOS",
|
||||||
|
"name": "YsuOS",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/30138661?v=4",
|
||||||
|
"profile": "https://github.com/YsuOS",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "icecream17",
|
||||||
|
"name": "Steven Nguyen",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/58114641?v=4",
|
||||||
|
"profile": "https://lichess.org/@/StevenEmily",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "nacairns1",
|
||||||
|
"name": "nacairns1",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/94420090?v=4",
|
||||||
|
"profile": "https://noahcairns.dev",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "pgjbz",
|
||||||
|
"name": "Paulo Gabriel Justino Bezerra",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/22059237?v=4",
|
||||||
|
"profile": "https://github.com/pgjbz",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "jaystile",
|
||||||
|
"name": "Jason",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/46078028?v=4",
|
||||||
|
"profile": "https://github.com/jaystile",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "exdx",
|
||||||
|
"name": "exdx",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/31546601?v=4",
|
||||||
|
"profile": "https://exdx.github.io",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Jzow",
|
||||||
|
"name": "James Zow",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/68860495?v=4",
|
||||||
|
"profile": "https://github.com/Jzow",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "jayber",
|
||||||
|
"name": "James Bromley",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/2474334?v=4",
|
||||||
|
"profile": "https://jamesabromley.wordpress.com/",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "swhiteCQC",
|
||||||
|
"name": "swhiteCQC",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/77438466?v=4",
|
||||||
|
"profile": "https://github.com/swhiteCQC",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "neilpate",
|
||||||
|
"name": "Neil Pate",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/7802334?v=4",
|
||||||
|
"profile": "https://github.com/neilpate",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "wojexe",
|
||||||
|
"name": "wojexe",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/21208490?v=4",
|
||||||
|
"profile": "https://wojexe.com",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Tostapunk",
|
||||||
|
"name": "Mattia Schiavon",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/25140297?v=4",
|
||||||
|
"profile": "https://github.com/Tostapunk",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "PrettyWood",
|
||||||
|
"name": "Eric Jolibois",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/18406791?v=4",
|
||||||
|
"profile": "http://toucantoco.com",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "EdwinChang24",
|
||||||
|
"name": "Edwin Chang",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/88263098?v=4",
|
||||||
|
"profile": "http://edwinchang.vercel.app",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "saikatdas0790",
|
||||||
|
"name": "Saikat Das",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/7412443?v=4",
|
||||||
|
"profile": "https://saikat.dev/",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "thatlittleboy",
|
||||||
|
"name": "Jeremy Goh",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/30731072?v=4",
|
||||||
|
"profile": "https://github.com/thatlittleboy",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Lioness100",
|
||||||
|
"name": "Lioness100",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/65814829?v=4",
|
||||||
|
"profile": "https://github.com/Lioness100",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "tvkn",
|
||||||
|
"name": "Tristan Nicholls",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/79277926?v=4",
|
||||||
|
"profile": "https://github.com/tvkn",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "clairew",
|
||||||
|
"name": "Claire",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/9344258?v=4",
|
||||||
|
"profile": "http://clairewang.net",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 8,
|
"contributorsPerLine": 8,
|
||||||
|
|||||||
@ -2,6 +2,6 @@ root = true
|
|||||||
|
|
||||||
[*.rs]
|
[*.rs]
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
insert_final_newfile = true
|
insert_final_newline = true
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|||||||
20
.github/workflows/rust.yml
vendored
Normal file
20
.github/workflows/rust.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
name: Rustlings Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Build
|
||||||
|
run: cargo build --verbose
|
||||||
|
- name: Run tests
|
||||||
|
run: cargo test --verbose
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,6 +5,8 @@ target/
|
|||||||
*.pdb
|
*.pdb
|
||||||
exercises/clippy/Cargo.toml
|
exercises/clippy/Cargo.toml
|
||||||
exercises/clippy/Cargo.lock
|
exercises/clippy/Cargo.lock
|
||||||
|
rust-project.json
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
*.iml
|
*.iml
|
||||||
|
*.o
|
||||||
|
|||||||
31
AUTHORS.md
31
AUTHORS.md
@ -175,6 +175,37 @@ authors.
|
|||||||
<td align="center"><a href="https://github.com/merelymyself"><img src="https://avatars.githubusercontent.com/u/88221256?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pwygab</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=merelymyself" title="Code">💻</a></td>
|
<td align="center"><a href="https://github.com/merelymyself"><img src="https://avatars.githubusercontent.com/u/88221256?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pwygab</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=merelymyself" title="Code">💻</a></td>
|
||||||
<td align="center"><a href="http://linkedin.com/in/lucasgrvarela"><img src="https://avatars.githubusercontent.com/u/37870368?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lucas Grigolon Varela</b></sub></a><br /><a href="#content-lucasgrvarela" title="Content">🖋</a></td>
|
<td align="center"><a href="http://linkedin.com/in/lucasgrvarela"><img src="https://avatars.githubusercontent.com/u/37870368?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lucas Grigolon Varela</b></sub></a><br /><a href="#content-lucasgrvarela" title="Content">🖋</a></td>
|
||||||
<td align="center"><a href="https://github.com/bufo24"><img src="https://avatars.githubusercontent.com/u/32884105?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bufo</b></sub></a><br /><a href="#content-bufo24" title="Content">🖋</a></td>
|
<td align="center"><a href="https://github.com/bufo24"><img src="https://avatars.githubusercontent.com/u/32884105?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bufo</b></sub></a><br /><a href="#content-bufo24" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="http://rustnote.com"><img src="https://avatars.githubusercontent.com/u/77730378?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jack Clayton</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=jackos" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/klkl0808"><img src="https://avatars.githubusercontent.com/u/24694249?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Konstantin</b></sub></a><br /><a href="#content-klkl0808" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/0pling"><img src="https://avatars.githubusercontent.com/u/104090344?v=4?s=100" width="100px;" alt=""/><br /><sub><b>0pling</b></sub></a><br /><a href="#content-0pling" title="Content">🖋</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://github.com/KatanaFluorescent"><img src="https://avatars.githubusercontent.com/u/60199077?v=4?s=100" width="100px;" alt=""/><br /><sub><b>KatanaFluorescent</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=KatanaFluorescent" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Drew-Morris"><img src="https://avatars.githubusercontent.com/u/95818166?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Drew Morris</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Drew-Morris" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/camperdue42"><img src="https://avatars.githubusercontent.com/u/43047763?v=4?s=100" width="100px;" alt=""/><br /><sub><b>camperdue42</b></sub></a><br /><a href="#content-camperdue42" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/YsuOS"><img src="https://avatars.githubusercontent.com/u/30138661?v=4?s=100" width="100px;" alt=""/><br /><sub><b>YsuOS</b></sub></a><br /><a href="#content-YsuOS" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://lichess.org/@/StevenEmily"><img src="https://avatars.githubusercontent.com/u/58114641?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Steven Nguyen</b></sub></a><br /><a href="#content-icecream17" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://noahcairns.dev"><img src="https://avatars.githubusercontent.com/u/94420090?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nacairns1</b></sub></a><br /><a href="#content-nacairns1" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/pgjbz"><img src="https://avatars.githubusercontent.com/u/22059237?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Paulo Gabriel Justino Bezerra</b></sub></a><br /><a href="#content-pgjbz" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/jaystile"><img src="https://avatars.githubusercontent.com/u/46078028?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jason</b></sub></a><br /><a href="#content-jaystile" title="Content">🖋</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://exdx.github.io"><img src="https://avatars.githubusercontent.com/u/31546601?v=4?s=100" width="100px;" alt=""/><br /><sub><b>exdx</b></sub></a><br /><a href="#content-exdx" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Jzow"><img src="https://avatars.githubusercontent.com/u/68860495?v=4?s=100" width="100px;" alt=""/><br /><sub><b>James Zow</b></sub></a><br /><a href="#content-Jzow" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://jamesabromley.wordpress.com/"><img src="https://avatars.githubusercontent.com/u/2474334?v=4?s=100" width="100px;" alt=""/><br /><sub><b>James Bromley</b></sub></a><br /><a href="#content-jayber" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/swhiteCQC"><img src="https://avatars.githubusercontent.com/u/77438466?v=4?s=100" width="100px;" alt=""/><br /><sub><b>swhiteCQC</b></sub></a><br /><a href="#content-swhiteCQC" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/neilpate"><img src="https://avatars.githubusercontent.com/u/7802334?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Neil Pate</b></sub></a><br /><a href="#content-neilpate" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://wojexe.com"><img src="https://avatars.githubusercontent.com/u/21208490?v=4?s=100" width="100px;" alt=""/><br /><sub><b>wojexe</b></sub></a><br /><a href="#content-wojexe" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Tostapunk"><img src="https://avatars.githubusercontent.com/u/25140297?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mattia Schiavon</b></sub></a><br /><a href="#content-Tostapunk" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="http://toucantoco.com"><img src="https://avatars.githubusercontent.com/u/18406791?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Eric Jolibois</b></sub></a><br /><a href="#content-PrettyWood" title="Content">🖋</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="http://edwinchang.vercel.app"><img src="https://avatars.githubusercontent.com/u/88263098?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Edwin Chang</b></sub></a><br /><a href="#content-EdwinChang24" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://saikat.dev/"><img src="https://avatars.githubusercontent.com/u/7412443?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Saikat Das</b></sub></a><br /><a href="#content-saikatdas0790" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/thatlittleboy"><img src="https://avatars.githubusercontent.com/u/30731072?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jeremy Goh</b></sub></a><br /><a href="#content-thatlittleboy" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Lioness100"><img src="https://avatars.githubusercontent.com/u/65814829?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lioness100</b></sub></a><br /><a href="#content-Lioness100" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/tvkn"><img src="https://avatars.githubusercontent.com/u/79277926?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tristan Nicholls</b></sub></a><br /><a href="#content-tvkn" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="http://clairewang.net"><img src="https://avatars.githubusercontent.com/u/9344258?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Claire</b></sub></a><br /><a href="#content-clairew" title="Content">🖋</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
94
CHANGELOG.md
94
CHANGELOG.md
@ -1,3 +1,97 @@
|
|||||||
|
<a name="5.0.0"></a>
|
||||||
|
## 5.0.0 (2022-07-16)
|
||||||
|
|
||||||
|
#### Features
|
||||||
|
|
||||||
|
- Hint comments in exercises now also include a reference to the
|
||||||
|
`hint` watch mode subcommand.
|
||||||
|
- **intro1**: Added more hints to point the user to the source file.
|
||||||
|
- **variables**: Switched variables3 and variables4.
|
||||||
|
- Moved `vec` and `primitive_types` exercises before `move_semantics`.
|
||||||
|
- Renamed `vec` to `vecs` to be more in line with the naming in general.
|
||||||
|
- Split up the `collections` exercises in their own folders.
|
||||||
|
- **vec2**: Added a second part of the function that provides an alternative,
|
||||||
|
immutable way of modifying vec values.
|
||||||
|
- **enums3**: Added a hint.
|
||||||
|
- Moved `strings` before `modules`.
|
||||||
|
- Added a `strings3` exercise to teach modifying strings.
|
||||||
|
- Added a `hashmaps3` exercise for some advanced usage of hashmaps.
|
||||||
|
- Moved the original `quiz2` to be `strings4`, since it only tested strings
|
||||||
|
anyways.
|
||||||
|
- Reworked `quiz2` into a new exercise that tests more chapters.
|
||||||
|
- Renamed `option` to `options`.
|
||||||
|
- **options1**: Rewrote parts of the exercise to remove the weird array
|
||||||
|
iteration stuff.
|
||||||
|
- Moved `generics3` to be `quiz3`.
|
||||||
|
- Moved box/arc exercises behind `iterators`.
|
||||||
|
- **iterators4**: Added a test for factorials of zero.
|
||||||
|
- Split `threads1` between two exercises, the first one focusing more on
|
||||||
|
`JoinHandle`s.
|
||||||
|
- Added a `threads3` exercises that uses `std::sync::mpsc`.
|
||||||
|
- Added a `clippy3` exercises with some more interesting checks.
|
||||||
|
- **as_ref_mut**: Added a section that actually tests `AsMut`.
|
||||||
|
- Added 3 new lifetimes exercises.
|
||||||
|
- Added 3 new traits exercises.
|
||||||
|
|
||||||
|
#### Bug Fixes
|
||||||
|
|
||||||
|
- **variables2**: Made output messages more verbose.
|
||||||
|
- **variables5**: Added a nudging hint about shadowing.
|
||||||
|
- **variables6**: Fixed link to book.
|
||||||
|
- **functions**: Clarified the README wording. Generally cleaned up
|
||||||
|
some hints and added some extra comments.
|
||||||
|
- **if2**: Renamed function name to `foo_if_fizz`.
|
||||||
|
- **move_semantics**: Clarified some hints.
|
||||||
|
- **quiz1**: Renamed the function name to be more verbose.
|
||||||
|
- **structs1**: Use an integer type instead of strings. Renamed "unit structs"
|
||||||
|
to "unit-like structs", as is used in the book.
|
||||||
|
- **structs3**: Added the `panic!` statement in from the beginning.
|
||||||
|
- **errors1**: Use `is_empty()` instead of `len() > 0`
|
||||||
|
- **errors3**: Improved the hint.
|
||||||
|
- **errors5**: Improved exercise instructions and the hint.
|
||||||
|
- **errors6**: Provided the skeleton of one of the functions that's supposed
|
||||||
|
to be implemented.
|
||||||
|
- **iterators3**: Inserted `todo!` into `divide()` to keep a compiler error
|
||||||
|
from happening.
|
||||||
|
- **from_str**: Added a hint comment about string error message conversion with
|
||||||
|
`Box<dyn Error>`.
|
||||||
|
- **try_from_into**: Fixed the function name in comment.
|
||||||
|
|
||||||
|
#### Removed
|
||||||
|
|
||||||
|
- Removed the legacy LSP feature that was using `mod.rs` files.
|
||||||
|
- Removed `quiz4`.
|
||||||
|
- Removed `advanced_errs`. These were the last exercises in the recommended
|
||||||
|
order, and I've always felt like they didn't quite fit in with the mostly
|
||||||
|
simple, book-following style we've had in Rustlings.
|
||||||
|
|
||||||
|
#### Housekeeping
|
||||||
|
|
||||||
|
- Added missing exercises to the book index.
|
||||||
|
- Updated spacing in Cargo.toml.
|
||||||
|
- Added a GitHub actions config so that tests run on every PR/commit.
|
||||||
|
|
||||||
|
<a name="4.8.0"></a>
|
||||||
|
## 4.8.0 (2022-07-01)
|
||||||
|
|
||||||
|
#### Features
|
||||||
|
|
||||||
|
- Added a progress indicator for `rustlings watch`.
|
||||||
|
- The installation script now checks for Rustup being installed.
|
||||||
|
- Added a `rustlings lsp` command to enable `rust-analyzer`.
|
||||||
|
|
||||||
|
#### Bug Fixes
|
||||||
|
|
||||||
|
- **move_semantics5**: Replaced "in vogue" with "in scope" in hint.
|
||||||
|
- **if2**: Fixed a typo in the hint.
|
||||||
|
- **variables1**: Fixed an incorrect line reference in the hint.
|
||||||
|
- Fixed an out of bounds check in the installation Bash script.
|
||||||
|
|
||||||
|
#### Housekeeping
|
||||||
|
|
||||||
|
- Replaced the git.io URL with the fully qualified URL because of git.io's sunsetting.
|
||||||
|
- Removed the deprecated Rust GitPod extension.
|
||||||
|
|
||||||
<a name="4.7.1"></a>
|
<a name="4.7.1"></a>
|
||||||
## 4.7.1 (2022-04-20)
|
## 4.7.1 (2022-04-20)
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ _implement a new feature! ➡️ [open an Issue to discuss it first, then a Pull
|
|||||||
|
|
||||||
`rustlings` is basically a glorified `rustc` wrapper. Therefore 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`.
|
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`.
|
`src/main.rs` contains a simple `argh` CLI that connects to most of the other source files.
|
||||||
|
|
||||||
<a name="addex"></a>
|
<a name="addex"></a>
|
||||||
### Adding an exercise
|
### Adding an exercise
|
||||||
@ -29,7 +29,7 @@ isn't really that complicated since the bulk of the work is done by `rustc`.
|
|||||||
The first step is to add the exercise! Name the file `exercises/yourTopic/yourTopicN.rs`, make sure to
|
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`.
|
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`.
|
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` and `rustlings watch`.
|
||||||
|
|
||||||
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:
|
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
|
```diff
|
||||||
@ -43,7 +43,7 @@ Add the metadata for your exercise in the correct order in the `exercises` array
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
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`.
|
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`. If you're working on a Clippy exercise, use `mode = "clippy"`.
|
||||||
|
|
||||||
That's all! Feel free to put up a pull request.
|
That's all! Feel free to put up a pull request.
|
||||||
|
|
||||||
@ -67,19 +67,19 @@ changes. There's a couple of things to watch out for:
|
|||||||
#### Write correct commit messages
|
#### Write correct commit messages
|
||||||
|
|
||||||
We follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.4/)
|
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.
|
specification.
|
||||||
This means that you have to format your commit messages in a specific way. Say
|
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
|
you're working on adding a new exercise called `foobar1.rs`. You could write
|
||||||
the following commit message:
|
the following commit message:
|
||||||
|
|
||||||
```
|
```
|
||||||
feat: Add foobar1.rs exercise
|
feat: add foobar1.rs exercise
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're just fixing a bug, please use the `fix` type:
|
If you're just fixing a bug, please use the `fix` type:
|
||||||
|
|
||||||
```
|
```
|
||||||
fix(verify): Make sure verify doesn't self-destruct
|
fix(verify): make sure verify doesn't self-destruct
|
||||||
```
|
```
|
||||||
|
|
||||||
The scope within the brackets is optional, but should be any of these:
|
The scope within the brackets is optional, but should be any of these:
|
||||||
@ -96,7 +96,7 @@ When the commit also happens to close an existing issue, link it in the message
|
|||||||
body:
|
body:
|
||||||
|
|
||||||
```
|
```
|
||||||
fix: Update foobar
|
fix: update foobar
|
||||||
|
|
||||||
closes #101029908
|
closes #101029908
|
||||||
```
|
```
|
||||||
@ -104,13 +104,13 @@ closes #101029908
|
|||||||
If you're doing simple changes, like updating a book link, use `chore`:
|
If you're doing simple changes, like updating a book link, use `chore`:
|
||||||
|
|
||||||
```
|
```
|
||||||
chore: Update exercise1.rs book link
|
chore: update exercise1.rs book link
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're updating documentation, use `docs`:
|
If you're updating documentation, use `docs`:
|
||||||
|
|
||||||
```
|
```
|
||||||
docs: Add more information to Readme
|
docs: add more information to Readme
|
||||||
```
|
```
|
||||||
|
|
||||||
If, and only if, you're absolutely sure you want to make a breaking change
|
If, and only if, you're absolutely sure you want to make a breaking change
|
||||||
@ -118,7 +118,7 @@ If, and only if, you're absolutely sure you want to make a breaking change
|
|||||||
explain the breaking change in the message body:
|
explain the breaking change in the message body:
|
||||||
|
|
||||||
```
|
```
|
||||||
fix!: Completely change verification
|
fix!: completely change verification
|
||||||
|
|
||||||
BREAKING CHANGE: This has to be done because lorem ipsum dolor
|
BREAKING CHANGE: This has to be done because lorem ipsum dolor
|
||||||
```
|
```
|
||||||
@ -126,6 +126,5 @@ BREAKING CHANGE: This has to be done because lorem ipsum dolor
|
|||||||
#### Pull Request Workflow
|
#### Pull Request Workflow
|
||||||
|
|
||||||
Once you open a Pull Request, it may be reviewed or labeled (or both) until
|
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
|
the maintainers accept your change. Please be patient, it may take some time
|
||||||
run the test suite with your changes and if it's successful, automatically
|
for this to happen!
|
||||||
merge it in!
|
|
||||||
|
|||||||
21
Cargo.lock
generated
21
Cargo.lock
generated
@ -186,6 +186,15 @@ dependencies = [
|
|||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "home"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indicatif"
|
name = "indicatif"
|
||||||
version = "0.16.2"
|
version = "0.16.2"
|
||||||
@ -229,9 +238,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "0.4.8"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kernel32-sys"
|
name = "kernel32-sys"
|
||||||
@ -450,17 +459,19 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustlings"
|
name = "rustlings"
|
||||||
version = "4.7.1"
|
version = "5.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argh",
|
"argh",
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
"console",
|
"console",
|
||||||
"glob",
|
"glob",
|
||||||
|
"home",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"notify",
|
"notify",
|
||||||
"predicates",
|
"predicates",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -501,9 +512,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.66"
|
version = "1.0.81"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127"
|
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
|
|||||||
12
Cargo.toml
12
Cargo.toml
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rustlings"
|
name = "rustlings"
|
||||||
version = "4.7.1"
|
version = "5.0.0"
|
||||||
authors = ["mokou <mokou@fastmail.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
|
authors = ["Liv <mokou@fastmail.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@ -11,7 +11,10 @@ console = "0.15"
|
|||||||
notify = "4.0"
|
notify = "4.0"
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
regex = "1.5"
|
regex = "1.5"
|
||||||
serde= { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0.81"
|
||||||
|
home = "0.5.3"
|
||||||
|
glob = "0.3.0"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "rustlings"
|
name = "rustlings"
|
||||||
@ -21,6 +24,3 @@ path = "src/main.rs"
|
|||||||
assert_cmd = "0.11.0"
|
assert_cmd = "0.11.0"
|
||||||
predicates = "1.0.1"
|
predicates = "1.0.1"
|
||||||
glob = "0.3.0"
|
glob = "0.3.0"
|
||||||
|
|
||||||
[features]
|
|
||||||
exercises = []
|
|
||||||
|
|||||||
47
README.md
47
README.md
@ -44,9 +44,9 @@ Start-BitsTransfer -Source https://raw.githubusercontent.com/rust-lang/rustlings
|
|||||||
|
|
||||||
To install Rustlings. Same as on MacOS/Linux, you will have access to the `rustlings` command after it.
|
To install Rustlings. Same as on MacOS/Linux, you will have access to the `rustlings` command after it.
|
||||||
|
|
||||||
When you get a permission denied message then you have to exclude the directory where you placed the rustlings in your virus-scanner
|
If you get a permission denied message, you might have to exclude the directory where you cloned Rustlings in your antivirus.
|
||||||
|
|
||||||
## Browser:
|
## Browser
|
||||||
|
|
||||||
[Run on Repl.it](https://repl.it/github/rust-lang/rustlings)
|
[Run on Repl.it](https://repl.it/github/rust-lang/rustlings)
|
||||||
|
|
||||||
@ -54,11 +54,11 @@ When you get a permission denied message then you have to exclude the directory
|
|||||||
|
|
||||||
## Manually
|
## Manually
|
||||||
|
|
||||||
Basically: Clone the repository at the latest tag, run `cargo install`.
|
Basically: Clone the repository at the latest tag, run `cargo install --path .`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 4.7.1)
|
# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.0.0)
|
||||||
git clone -b 4.7.1 --depth 1 https://github.com/rust-lang/rustlings
|
git clone -b 5.0.0 --depth 1 https://github.com/rust-lang/rustlings
|
||||||
cd rustlings
|
cd rustlings
|
||||||
cargo install --force --path .
|
cargo install --force --path .
|
||||||
```
|
```
|
||||||
@ -126,24 +126,7 @@ After every couple of sections, there will be a quiz that'll test your knowledge
|
|||||||
|
|
||||||
## Enabling `rust-analyzer`
|
## Enabling `rust-analyzer`
|
||||||
|
|
||||||
`rust-analyzer` support is provided, but it depends on your editor
|
Run the command `rustlings lsp` which will generate a `rust-project.json` at the root of the project, this allows [rust-analyzer](https://rust-analyzer.github.io/) to parse each exercise.
|
||||||
whether it's enabled by default. (RLS support is not provided)
|
|
||||||
|
|
||||||
To enable `rust-analyzer`, you'll need to make Cargo build the project
|
|
||||||
with the `exercises` feature, which will automatically include the `exercises/`
|
|
||||||
subfolder in the project. The easiest way to do this is to tell your editor to
|
|
||||||
build the project with all features (the equivalent of `cargo build --all-features`).
|
|
||||||
For specific editor instructions:
|
|
||||||
|
|
||||||
- **VSCode**: Add a `.vscode/settings.json` file with the following:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"rust-analyzer.cargo.features": ["exercises"]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- **IntelliJ-based Editors**: Using the Rust plugin, everything should work
|
|
||||||
by default.
|
|
||||||
- _Missing your editor? Feel free to contribute more instructions!_
|
|
||||||
|
|
||||||
## Continuing On
|
## Continuing On
|
||||||
|
|
||||||
@ -167,24 +150,6 @@ cargo uninstall rustlings
|
|||||||
|
|
||||||
Now you should be done!
|
Now you should be done!
|
||||||
|
|
||||||
## Completion
|
|
||||||
|
|
||||||
Rustlings isn't done; there are a couple of sections that are very experimental and don't have proper documentation. These include:
|
|
||||||
|
|
||||||
- Errors (`exercises/errors/`)
|
|
||||||
- Option (`exercises/option/`)
|
|
||||||
- Result (`exercises/result/`)
|
|
||||||
- Move Semantics (could still be improved, `exercises/move_semantics/`)
|
|
||||||
|
|
||||||
Additionally, we could use exercises on a couple of topics:
|
|
||||||
|
|
||||||
- Structs
|
|
||||||
- Better ownership stuff
|
|
||||||
- `impl`
|
|
||||||
- ??? probably more
|
|
||||||
|
|
||||||
If you are interested in improving or adding new ones, please feel free to contribute! Read on for more information :)
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||||
|
|||||||
@ -1,24 +1,26 @@
|
|||||||
# Exercise to Book Chapter mapping
|
# Exercise to Book Chapter mapping
|
||||||
|
|
||||||
| Exercise | Book Chapter |
|
| Exercise | Book Chapter |
|
||||||
|------------------------|--------------|
|
| ---------------------- | ------------------- |
|
||||||
| variables | §3.1 |
|
| variables | §3.1 |
|
||||||
| functions | §3.3 |
|
| functions | §3.3 |
|
||||||
| if | §3.5 |
|
| if | §3.5 |
|
||||||
| move_semantics | §4.1 |
|
| primitive_types | §3.2, §4.3 |
|
||||||
| primitive_types | §4.3 |
|
| vecs | §8.1 |
|
||||||
| structs | §5.1 |
|
| move_semantics | §4.1, §4.2 |
|
||||||
| enums | §6 |
|
| structs | §5.1, §5.3 |
|
||||||
| modules | §7 |
|
| enums | §6, §18.3 |
|
||||||
| collections | §8.1, §8.3 |
|
| strings | §8.2 |
|
||||||
| strings | §8.2 |
|
| modules | §7 |
|
||||||
| error_handling | §9 |
|
| hashmaps | §8.3 |
|
||||||
| generics | §10 |
|
| options | §10.1 |
|
||||||
| option | §10.1 |
|
| error_handling | §9 |
|
||||||
| traits | §10.2 |
|
| generics | §10 |
|
||||||
| tests | §11.1 |
|
| traits | §10.2 |
|
||||||
| standard_library_types | §13.2 |
|
| tests | §11.1 |
|
||||||
| threads | §16.1 |
|
| lifetimes | §10.3 |
|
||||||
| macros | §19.6 |
|
| standard_library_types | §13.2, §15.1, §16.3 |
|
||||||
| clippy | n/a |
|
| threads | §16.1, §16.2, §16.3 |
|
||||||
| conversions | n/a |
|
| 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,2 +0,0 @@
|
|||||||
mod advanced_errs1;
|
|
||||||
mod advanced_errs2;
|
|
||||||
@ -4,7 +4,7 @@
|
|||||||
//
|
//
|
||||||
// For these exercises the code will fail to compile when there are clippy warnings
|
// 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.
|
// check clippy's suggestions from the output to solve the exercise.
|
||||||
// Execute `rustlings hint clippy1` for hints :)
|
// Execute `rustlings hint clippy1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
|
|
||||||
use std::f32;
|
use std::f32;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// clippy2.rs
|
// clippy2.rs
|
||||||
// Make me compile! Execute `rustlings hint clippy2` for hints :)
|
// Execute `rustlings hint clippy2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
28
exercises/clippy/clippy3.rs
Normal file
28
exercises/clippy/clippy3.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// clippy3.rs
|
||||||
|
// Here's a couple more easy Clippy fixes, so you can see its utility.
|
||||||
|
|
||||||
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
#[allow(unused_variables, unused_assignments)]
|
||||||
|
fn main() {
|
||||||
|
let my_option: Option<()> = None;
|
||||||
|
if my_option.is_none() {
|
||||||
|
my_option.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let my_arr = &[
|
||||||
|
-1, -2, -3
|
||||||
|
-4, -5, -6
|
||||||
|
];
|
||||||
|
println!("My array! Here it is: {:?}", my_arr);
|
||||||
|
|
||||||
|
let my_empty_vec = vec![1, 2, 3, 4, 5].resize(0, 5);
|
||||||
|
println!("This Vec is empty, see? {:?}", my_empty_vec);
|
||||||
|
|
||||||
|
let mut value_a = 45;
|
||||||
|
let mut value_b = 66;
|
||||||
|
// Let's swap these two!
|
||||||
|
value_a = value_b;
|
||||||
|
value_b = value_a;
|
||||||
|
println!("value a: {}; value b: {}", value_a, value_b);
|
||||||
|
}
|
||||||
@ -1,2 +0,0 @@
|
|||||||
mod clippy1;
|
|
||||||
mod clippy2;
|
|
||||||
@ -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,4 +0,0 @@
|
|||||||
mod hashmap1;
|
|
||||||
mod hashmap2;
|
|
||||||
mod vec1;
|
|
||||||
mod vec2;
|
|
||||||
@ -1,6 +1,7 @@
|
|||||||
// AsRef and AsMut allow for cheap reference-to-reference conversions.
|
// 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
|
// 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.
|
// and https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively.
|
||||||
|
// Execute `rustlings hint as_ref_mut` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
@ -16,10 +17,10 @@ fn char_counter<T>(arg: T) -> usize {
|
|||||||
arg.as_ref().chars().count()
|
arg.as_ref().chars().count()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
// Squares a number using AsMut. Add the trait bound as is appropriate and
|
||||||
let s = "Café au lait";
|
// implement the function body.
|
||||||
println!("{}", char_counter(s));
|
fn num_sq<T>(arg: &mut T) {
|
||||||
println!("{}", byte_counter(s));
|
???
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -49,4 +50,11 @@ mod tests {
|
|||||||
let s = String::from("Cafe au lait");
|
let s = String::from("Cafe au lait");
|
||||||
assert_eq!(char_counter(s.clone()), byte_counter(s));
|
assert_eq!(char_counter(s.clone()), byte_counter(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mult_box() {
|
||||||
|
let mut num: Box<u32> = Box::new(3);
|
||||||
|
num_sq(&mut num);
|
||||||
|
assert_eq!(*num, 9);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
// The From trait is used for value-to-value conversions.
|
// The From trait is used for value-to-value conversions.
|
||||||
// If From is implemented correctly for a type, the Into trait should work conversely.
|
// 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
|
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.From.html
|
||||||
|
// Execute `rustlings hint from_into` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Person {
|
struct Person {
|
||||||
name: String,
|
name: String,
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
// Additionally, upon implementing FromStr, you can use the `parse` method
|
// Additionally, upon implementing FromStr, you can use the `parse` method
|
||||||
// on strings to generate an object of the implementor type.
|
// 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
|
// You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html
|
||||||
|
// Execute `rustlings hint from_str` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
@ -37,6 +39,9 @@ enum ParsePersonError {
|
|||||||
// with something like `"4".parse::<usize>()`
|
// with something like `"4".parse::<usize>()`
|
||||||
// 6. If while extracting the name and the age something goes wrong, an error should be returned
|
// 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
|
// If everything goes well, then return a Result of a Person object
|
||||||
|
//
|
||||||
|
// As an aside: `Box<dyn Error>` implements `From<&'_ str>`. This means that if you want to return a
|
||||||
|
// string error message, you can do so via just using return `Err("my error message".into())`.
|
||||||
|
|
||||||
impl FromStr for Person {
|
impl FromStr for Person {
|
||||||
type Err = ParsePersonError;
|
type Err = ParsePersonError;
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
mod as_ref_mut;
|
|
||||||
mod from_into;
|
|
||||||
mod from_str;
|
|
||||||
mod try_from_into;
|
|
||||||
mod using_as;
|
|
||||||
@ -3,6 +3,8 @@
|
|||||||
// Basically, this is the same as From. The main difference is that this should return a Result type
|
// Basically, this is the same as From. The main difference is that this should return a Result type
|
||||||
// instead of the target type itself.
|
// instead of the target type itself.
|
||||||
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
|
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
|
||||||
|
// Execute `rustlings hint try_from_into` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -54,7 +56,7 @@ impl TryFrom<&[i16]> for Color {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Use the `from` function
|
// Use the `try_from` function
|
||||||
let c1 = Color::try_from((183, 65, 14));
|
let c1 = Color::try_from((183, 65, 14));
|
||||||
println!("{:?}", c1);
|
println!("{:?}", c1);
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
//
|
//
|
||||||
// The goal is to make sure that the division does not fail to compile
|
// The goal is to make sure that the division does not fail to compile
|
||||||
// and returns the proper type.
|
// and returns the proper type.
|
||||||
|
// Execute `rustlings hint using_as` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// enums1.rs
|
// enums1.rs
|
||||||
// Make me compile! Execute `rustlings hint enums1` for hints!
|
// No hints this time! ;)
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// enums2.rs
|
// enums2.rs
|
||||||
// Make me compile! Execute `rustlings hint enums2` for hints!
|
// Execute `rustlings hint enums2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// enums3.rs
|
// enums3.rs
|
||||||
// Address all the TODOs to make the tests pass!
|
// Address all the TODOs to make the tests pass!
|
||||||
|
// Execute `rustlings hint enums3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
mod enums1;
|
|
||||||
mod enums2;
|
|
||||||
mod enums3;
|
|
||||||
@ -3,16 +3,16 @@
|
|||||||
// you pass it an empty string. It'd be nicer if it explained what the problem
|
// you pass it an empty string. It'd be nicer if it explained what the problem
|
||||||
// was, instead of just sometimes returning `None`. Thankfully, Rust has a similar
|
// was, instead of just sometimes returning `None`. Thankfully, Rust has a similar
|
||||||
// construct to `Option` that can be used to express error conditions. Let's use it!
|
// construct to `Option` that can be used to express error conditions. Let's use it!
|
||||||
// Execute `rustlings hint errors1` for hints!
|
// Execute `rustlings hint errors1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
pub fn generate_nametag_text(name: String) -> Option<String> {
|
pub fn generate_nametag_text(name: String) -> Option<String> {
|
||||||
if name.len() > 0 {
|
if name.is_empty() {
|
||||||
Some(format!("Hi! My name is {}", name))
|
|
||||||
} else {
|
|
||||||
// Empty names aren't allowed.
|
// Empty names aren't allowed.
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
Some(format!("Hi! My name is {}", name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,8 @@
|
|||||||
// and add.
|
// and add.
|
||||||
|
|
||||||
// There are at least two ways to implement this that are both correct-- but
|
// 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.
|
// one is a lot shorter!
|
||||||
|
// Execute `rustlings hint errors2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// This is a program that is trying to use a completed version of the
|
// 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!
|
// `total_cost` function from the previous exercise. It's not working though!
|
||||||
// Why not? What should we do to fix it?
|
// Why not? What should we do to fix it?
|
||||||
// Execute `rustlings hint errors3` for hints!
|
// Execute `rustlings hint errors3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// errors4.rs
|
// errors4.rs
|
||||||
// Make this test pass! Execute `rustlings hint errors4` for hints :)
|
// Execute `rustlings hint errors4` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
@ -14,6 +14,7 @@ enum CreationError {
|
|||||||
|
|
||||||
impl PositiveNonzeroInteger {
|
impl PositiveNonzeroInteger {
|
||||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
||||||
|
// Hmm...? Why is this only returning an Ok value?
|
||||||
Ok(PositiveNonzeroInteger(value as u64))
|
Ok(PositiveNonzeroInteger(value as u64))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,20 @@
|
|||||||
// errors5.rs
|
// errors5.rs
|
||||||
|
|
||||||
// This program uses a completed version of the code from errors4.
|
// This program uses an altered version of the code from errors4.
|
||||||
// It won't compile right now! Why?
|
|
||||||
// Execute `rustlings hint errors5` for hints!
|
// This exercise uses some concepts that we won't get to until later in the course, like `Box` and the
|
||||||
|
// `From` trait. It's not important to understand them in detail right now, but you can read ahead if you like.
|
||||||
|
// For now, think of the `Box<dyn ...>` type as an "I want anything that does ???" type, which, given
|
||||||
|
// Rust's usual standards for runtime safety, should strike you as somewhat lenient!
|
||||||
|
|
||||||
|
// In short, this particular use case for boxes is for when you want to own a value and you care only that it is a
|
||||||
|
// type which implements a particular trait. To do so, The Box is declared as of type Box<dyn Trait> where Trait is the trait
|
||||||
|
// the compiler looks for on any value used in that context. For this exercise, that context is the potential errors
|
||||||
|
// which can be returned in a Result.
|
||||||
|
|
||||||
|
// What can we use to describe both errors? In other words, is there a trait which both errors implement?
|
||||||
|
|
||||||
|
// Execute `rustlings hint errors5` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
@ -11,7 +23,7 @@ use std::fmt;
|
|||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
|
|
||||||
// TODO: update the return type of `main()` to make this compile.
|
// TODO: update the return type of `main()` to make this compile.
|
||||||
fn main() -> Result<(), ParseIntError> {
|
fn main() -> Result<(), Box<dyn ???>> {
|
||||||
let pretend_user_input = "42";
|
let pretend_user_input = "42";
|
||||||
let x: i64 = pretend_user_input.parse()?;
|
let x: i64 = pretend_user_input.parse()?;
|
||||||
println!("output={:?}", PositiveNonzeroInteger::new(x)?);
|
println!("output={:?}", PositiveNonzeroInteger::new(x)?);
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
// we define a custom error type to make it possible for callers to decide
|
// we define a custom error type to make it possible for callers to decide
|
||||||
// what to do next when our function returns an error.
|
// what to do next when our function returns an error.
|
||||||
|
|
||||||
// Make these tests pass! Execute `rustlings hint errors6` for hints :)
|
// Execute `rustlings hint errors6` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
@ -20,7 +20,11 @@ enum ParsePosNonzeroError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ParsePosNonzeroError {
|
impl ParsePosNonzeroError {
|
||||||
|
fn from_creation(err: CreationError) -> ParsePosNonzeroError {
|
||||||
|
ParsePosNonzeroError::Creation(err)
|
||||||
|
}
|
||||||
// TODO: add another error conversion function here.
|
// TODO: add another error conversion function here.
|
||||||
|
// fn from_parseint...
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pos_nonzero(s: &str)
|
fn parse_pos_nonzero(s: &str)
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
mod errors1;
|
|
||||||
mod errors2;
|
|
||||||
mod errors3;
|
|
||||||
mod errors4;
|
|
||||||
mod errors5;
|
|
||||||
mod errors6;
|
|
||||||
@ -1,6 +1,7 @@
|
|||||||
# Functions
|
# Functions
|
||||||
|
|
||||||
Here, you'll learn how to write functions and how Rust's compiler can trace things way back.
|
Here, you'll learn how to write functions and how the Rust compiler can help you debug errors even
|
||||||
|
in more complex code.
|
||||||
|
|
||||||
## Further information
|
## Further information
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// functions1.rs
|
// functions1.rs
|
||||||
// Make me compile! Execute `` for hints :)
|
// Make me compile! Execute `` for hints :)
|
||||||
|
// Execute `rustlings hint functions1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
|
|
||||||
fn call_me(){}
|
fn call_me(){}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// functions2.rs
|
// functions2.rs
|
||||||
// Make me compile! Execute `rustlings hint functions2` for hints :)
|
// Execute `rustlings hint functions2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// functions3.rs
|
// functions3.rs
|
||||||
// Make me compile! Execute `rustlings hint functions3` for hints :)
|
// Execute `rustlings hint functions3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
call_me(5);
|
call_me(5);
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
// functions4.rs
|
// functions4.rs
|
||||||
// Make me compile! Execute `rustlings hint functions4` for hints :)
|
// Execute `rustlings hint functions4` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// This store is having a sale where if the price is an even number, you get
|
// This store is having a sale where if the price is an even number, you get
|
||||||
// 10 Rustbucks off, but if it's an odd number, it's 3 Rustbucks off.
|
// 10 Rustbucks off, but if it's an odd number, it's 3 Rustbucks off.
|
||||||
|
// (Don't worry about the function bodies themselves, we're only interested
|
||||||
|
// in the signatures for now. If anything, this is a good way to peek ahead
|
||||||
|
// to future exercises!)
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
// functions5.rs
|
// functions5.rs
|
||||||
// Make me compile! Execute `rustlings hint functions5` for hints :)
|
// Execute `rustlings hint functions5` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let answer = square(3);
|
let answer = square(3);
|
||||||
println!("The answer is {}", answer);
|
println!("The square of 3 is {}", answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn square(num: i32) -> i32 {
|
fn square(num: i32) -> i32 {
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
mod functions1;
|
|
||||||
mod functions2;
|
|
||||||
mod functions3;
|
|
||||||
mod functions4;
|
|
||||||
mod functions5;
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
// This shopping list program isn't compiling!
|
// This shopping list program isn't compiling!
|
||||||
// Use your knowledge of generics to fix it.
|
// Use your knowledge of generics to fix it.
|
||||||
|
|
||||||
// Execute `rustlings hint generics1` for hints!
|
// Execute `rustlings hint generics1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
// This powerful wrapper provides the ability to store a positive integer value.
|
// This powerful wrapper provides the ability to store a positive integer value.
|
||||||
// Rewrite it using generics so that it supports wrapping ANY type.
|
// Rewrite it using generics so that it supports wrapping ANY type.
|
||||||
|
|
||||||
// Execute `rustlings hint generics2` for hints!
|
// Execute `rustlings hint generics2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -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,3 +0,0 @@
|
|||||||
mod generics1;
|
|
||||||
mod generics2;
|
|
||||||
mod generics3;
|
|
||||||
11
exercises/hashmaps/README.md
Normal file
11
exercises/hashmaps/README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Hashmaps
|
||||||
|
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.
|
||||||
|
|
||||||
|
This is the other data structure that we've been talking about before, when
|
||||||
|
talking about Vecs.
|
||||||
|
|
||||||
|
## Further information
|
||||||
|
|
||||||
|
- [Storing Keys with Associated Values in Hash Maps](https://doc.rust-lang.org/book/ch08-03-hash-maps.html)
|
||||||
@ -1,4 +1,4 @@
|
|||||||
// hashmap1.rs
|
// hashmaps1.rs
|
||||||
// A basket of fruits in the form of a hash map needs to be defined.
|
// 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
|
// 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
|
// how many of that particular fruit is in the basket. You have to put
|
||||||
@ -8,8 +8,7 @@
|
|||||||
//
|
//
|
||||||
// Make me compile and pass the tests!
|
// Make me compile and pass the tests!
|
||||||
//
|
//
|
||||||
// Execute the command `rustlings hint hashmap1` if you need
|
// Execute `rustlings hint hashmaps1` or use the `hint` watch subcommand for a hint.
|
||||||
// hints.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
// hashmap2.rs
|
// hashmaps2.rs
|
||||||
|
|
||||||
// A basket of fruits in the form of a hash map is given. The key
|
// 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
|
// represents the name of the fruit and the value represents how many
|
||||||
@ -9,8 +9,7 @@
|
|||||||
//
|
//
|
||||||
// Make me pass the tests!
|
// Make me pass the tests!
|
||||||
//
|
//
|
||||||
// Execute the command `rustlings hint hashmap2` if you need
|
// Execute `rustlings hint hashmaps2` or use the `hint` watch subcommand for a hint.
|
||||||
// hints.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
87
exercises/hashmaps/hashmaps3.rs
Normal file
87
exercises/hashmaps/hashmaps3.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// hashmaps3.rs
|
||||||
|
|
||||||
|
// A list of scores (one per line) of a soccer match is given. Each line
|
||||||
|
// is of the form :
|
||||||
|
// <team_1_name>,<team_2_name>,<team_1_goals>,<team_2_goals>
|
||||||
|
// Example: England,France,4,2 (England scored 4 goals, France 2).
|
||||||
|
|
||||||
|
// You have to build a scores table containing the name of the team, goals
|
||||||
|
// the team scored, and goals the team conceded. One approach to build
|
||||||
|
// the scores table is to use a Hashmap. The solution is partially
|
||||||
|
// written to use a Hashmap, complete it to pass the test.
|
||||||
|
|
||||||
|
// Make me pass the tests!
|
||||||
|
|
||||||
|
// Execute `rustlings hint hashmaps3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
// A structure to store team name and its goal details.
|
||||||
|
struct Team {
|
||||||
|
name: String,
|
||||||
|
goals_scored: u8,
|
||||||
|
goals_conceded: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_scores_table(results: String) -> HashMap<String, Team> {
|
||||||
|
// The name of the team is the key and its associated struct is the value.
|
||||||
|
let mut scores: HashMap<String, Team> = HashMap::new();
|
||||||
|
|
||||||
|
for r in results.lines() {
|
||||||
|
let v: Vec<&str> = r.split(',').collect();
|
||||||
|
let team_1_name = v[0].to_string();
|
||||||
|
let team_1_score: u8 = v[2].parse().unwrap();
|
||||||
|
let team_2_name = v[1].to_string();
|
||||||
|
let team_2_score: u8 = v[3].parse().unwrap();
|
||||||
|
// TODO: Populate the scores table with details extracted from the
|
||||||
|
// current line. Keep in mind that goals scored by team_1
|
||||||
|
// will be number of goals conceded from team_2, and similarly
|
||||||
|
// goals scored by team_2 will be the number of goals conceded by
|
||||||
|
// team_1.
|
||||||
|
}
|
||||||
|
scores
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn get_results() -> String {
|
||||||
|
let results = "".to_string()
|
||||||
|
+ "England,France,4,2\n"
|
||||||
|
+ "France,Italy,3,1\n"
|
||||||
|
+ "Poland,Spain,2,0\n"
|
||||||
|
+ "Germany,England,2,1\n";
|
||||||
|
results
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_scores() {
|
||||||
|
let scores = build_scores_table(get_results());
|
||||||
|
|
||||||
|
let mut keys: Vec<&String> = scores.keys().collect();
|
||||||
|
keys.sort();
|
||||||
|
assert_eq!(
|
||||||
|
keys,
|
||||||
|
vec!["England", "France", "Germany", "Italy", "Poland", "Spain"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_team_score_1() {
|
||||||
|
let scores = build_scores_table(get_results());
|
||||||
|
let team = scores.get("England").unwrap();
|
||||||
|
assert_eq!(team.goals_scored, 5);
|
||||||
|
assert_eq!(team.goals_conceded, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_team_score_2() {
|
||||||
|
let scores = build_scores_table(get_results());
|
||||||
|
let team = scores.get("Spain").unwrap();
|
||||||
|
assert_eq!(team.goals_scored, 0);
|
||||||
|
assert_eq!(team.goals_conceded, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
# If
|
# If
|
||||||
|
|
||||||
`if`, the most basic type of control flow, is what you'll learn here.
|
`if`, the most basic (but still surprisingly versatile!) type of control flow, is what you'll learn here.
|
||||||
|
|
||||||
## Further information
|
## Further information
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
// if1.rs
|
// if1.rs
|
||||||
|
// Execute `rustlings hint if1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
|
|
||||||
pub fn bigger(a: i32, b: i32) -> i32 {
|
pub fn bigger(a: i32, b: i32) -> i32 {
|
||||||
@ -11,7 +12,6 @@ pub fn bigger(a: i32, b: i32) -> i32 {
|
|||||||
// Do not use:
|
// Do not use:
|
||||||
// - another function call
|
// - another function call
|
||||||
// - additional variables
|
// - additional variables
|
||||||
// Execute `rustlings hint if1` for hints
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't mind this for now :)
|
// Don't mind this for now :)
|
||||||
|
|||||||
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
// Step 1: Make me compile!
|
// Step 1: Make me compile!
|
||||||
// Step 2: Get the bar_for_fuzz and default_to_baz tests passing!
|
// Step 2: Get the bar_for_fuzz and default_to_baz tests passing!
|
||||||
// Execute the command `rustlings hint if2` if you want a hint :)
|
// Execute `rustlings hint if2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
|
|
||||||
pub fn fizz_if_foo(fizzish: &str) -> &str {
|
pub fn foo_if_fizz(fizzish: &str) -> &str {
|
||||||
if fizzish == "fizz" {
|
if fizzish == "fizz" {
|
||||||
"foo"
|
"foo"
|
||||||
} else if fizzish == "fuzz" {
|
} else if fizzish == "fuzz" {
|
||||||
@ -22,16 +22,16 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn foo_for_fizz() {
|
fn foo_for_fizz() {
|
||||||
assert_eq!(fizz_if_foo("fizz"), "foo")
|
assert_eq!(foo_if_fizz("fizz"), "foo")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bar_for_fuzz() {
|
fn bar_for_fuzz() {
|
||||||
assert_eq!(fizz_if_foo("fuzz"), "bar")
|
assert_eq!(foo_if_fizz("fuzz"), "bar")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn default_to_baz() {
|
fn default_to_baz() {
|
||||||
assert_eq!(fizz_if_foo("literally anything"), "baz")
|
assert_eq!(foo_if_fizz("literally anything"), "baz")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
mod if1;
|
|
||||||
mod if2;
|
|
||||||
@ -3,7 +3,11 @@
|
|||||||
// We sometimes encourage you to keep trying things on a given exercise, even
|
// We sometimes encourage you to keep trying things on a given exercise, even
|
||||||
// after you already figured it out. If you got everything working and feel
|
// after you already figured it out. If you got everything working and feel
|
||||||
// ready for the next exercise, remove the `I AM NOT DONE` comment below.
|
// ready for the next exercise, remove the `I AM NOT DONE` comment below.
|
||||||
// Execute the command `rustlings hint intro1` for a hint.
|
// Execute `rustlings hint intro1` or use the `hint` watch subcommand for a hint.
|
||||||
|
//
|
||||||
|
// If you're running this using `rustlings watch`: The exercise file will be reloaded
|
||||||
|
// when you change one of the lines below! Try adding a `println!` line, or try changing
|
||||||
|
// what it outputs in your terminal. Try removing a semicolon and see what happens!
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello and");
|
println!("Hello and");
|
||||||
@ -18,4 +22,7 @@ fn main() {
|
|||||||
println!("This exercise compiles successfully. The remaining exercises contain a compiler");
|
println!("This exercise compiles successfully. The remaining exercises contain a compiler");
|
||||||
println!("or logic error. The central concept behind Rustlings is to fix these errors and");
|
println!("or logic error. The central concept behind Rustlings is to fix these errors and");
|
||||||
println!("solve the exercises. Good luck!");
|
println!("solve the exercises. Good luck!");
|
||||||
|
println!();
|
||||||
|
println!("The source for this exercise is in `exercises/intro/intro1.rs`. Have a look!");
|
||||||
|
println!("Going forward, the source of the exercises will always be in the success/failure output.");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// intro2.rs
|
// intro2.rs
|
||||||
// Make the code print a greeting to the world.
|
// Make the code print a greeting to the world.
|
||||||
// Execute `rustlings hint intro2` for a hint.
|
// Execute `rustlings hint intro2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello {}!", "world");
|
println!("Hello {}!", "world");
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
mod intro1;
|
|
||||||
mod intro2;
|
|
||||||
17
exercises/lifetimes/README.md
Normal file
17
exercises/lifetimes/README.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Lifetimes
|
||||||
|
|
||||||
|
Lifetimes tell the compiler how to check whether references live long
|
||||||
|
enough to be valid in any given situation. For example lifetimes say
|
||||||
|
"make sure parameter 'a' lives as long as parameter 'b' so that the return
|
||||||
|
value is valid".
|
||||||
|
|
||||||
|
They are only necessary on borrows, i.e. references,
|
||||||
|
since copied parameters or moves are owned in their scope and cannot
|
||||||
|
be referenced outside. Lifetimes mean that calling code of e.g. functions
|
||||||
|
can be checked to make sure their arguments are valid. Lifetimes are
|
||||||
|
restrictive of their callers.
|
||||||
|
|
||||||
|
## Further information
|
||||||
|
|
||||||
|
- [Validating References with Lifetimes](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html)
|
||||||
|
- [Lifetimes (in Rust By Example)](https://doc.rust-lang.org/stable/rust-by-example/scope/lifetime.html)
|
||||||
26
exercises/lifetimes/lifetimes1.rs
Normal file
26
exercises/lifetimes/lifetimes1.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// lifetimes1.rs
|
||||||
|
//
|
||||||
|
// The Rust compiler needs to know how to check whether supplied references are
|
||||||
|
// valid, so that it can let the programmer know if a reference is at risk
|
||||||
|
// of going out of scope before it is used. Remember, references are borrows
|
||||||
|
// and do not own their own data. What if their owner goes out of scope?
|
||||||
|
//
|
||||||
|
// Execute `rustlings hint lifetimes1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
fn longest(x: &str, y: &str) -> &str {
|
||||||
|
if x.len() > y.len() {
|
||||||
|
x
|
||||||
|
} else {
|
||||||
|
y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let string1 = String::from("abcd");
|
||||||
|
let string2 = "xyz";
|
||||||
|
|
||||||
|
let result = longest(string1.as_str(), string2);
|
||||||
|
println!("The longest string is {}", result);
|
||||||
|
}
|
||||||
27
exercises/lifetimes/lifetimes2.rs
Normal file
27
exercises/lifetimes/lifetimes2.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// lifetimes2.rs
|
||||||
|
//
|
||||||
|
// So if the compiler is just validating the references passed
|
||||||
|
// to the annotated parameters and the return type, what do
|
||||||
|
// we need to change?
|
||||||
|
//
|
||||||
|
// Execute `rustlings hint lifetimes2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
|
||||||
|
if x.len() > y.len() {
|
||||||
|
x
|
||||||
|
} else {
|
||||||
|
y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let string1 = String::from("long string is long");
|
||||||
|
let result;
|
||||||
|
{
|
||||||
|
let string2 = String::from("xyz");
|
||||||
|
result = longest(string1.as_str(), string2.as_str());
|
||||||
|
}
|
||||||
|
println!("The longest string is {}", result);
|
||||||
|
}
|
||||||
20
exercises/lifetimes/lifetimes3.rs
Normal file
20
exercises/lifetimes/lifetimes3.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// lifetimes3.rs
|
||||||
|
//
|
||||||
|
// Lifetimes are also needed when structs hold references.
|
||||||
|
//
|
||||||
|
// Execute `rustlings hint lifetimes3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
struct Book {
|
||||||
|
author: &str,
|
||||||
|
title: &str,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let name = String::from("Jill Smith");
|
||||||
|
let title = String::from("Fish Flying");
|
||||||
|
let book = Book { author: &name, title: &title };
|
||||||
|
|
||||||
|
println!("{} by {}", book.title, book.author);
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
// macros1.rs
|
// macros1.rs
|
||||||
// Make me compile! Execute `rustlings hint macros1` for hints :)
|
// Execute `rustlings hint macros1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// macros2.rs
|
// macros2.rs
|
||||||
// Make me compile! Execute `rustlings hint macros2` for hints :)
|
// Execute `rustlings hint macros2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// macros3.rs
|
// macros3.rs
|
||||||
// Make me compile, without taking the macro out of the module!
|
// Make me compile, without taking the macro out of the module!
|
||||||
// Execute `rustlings hint macros3` for hints :)
|
// Execute `rustlings hint macros3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// macros4.rs
|
// macros4.rs
|
||||||
// Make me compile! Execute `rustlings hint macros4` for hints :)
|
// Execute `rustlings hint macros4` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +0,0 @@
|
|||||||
mod macros1;
|
|
||||||
mod macros2;
|
|
||||||
mod macros3;
|
|
||||||
mod macros4;
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
mod advanced_errors;
|
|
||||||
mod clippy;
|
|
||||||
mod collections;
|
|
||||||
mod conversions;
|
|
||||||
mod enums;
|
|
||||||
mod error_handling;
|
|
||||||
mod functions;
|
|
||||||
mod generics;
|
|
||||||
mod r#if;
|
|
||||||
mod intro;
|
|
||||||
mod macros;
|
|
||||||
mod modules;
|
|
||||||
mod move_semantics;
|
|
||||||
mod option;
|
|
||||||
mod primitive_types;
|
|
||||||
mod quiz1;
|
|
||||||
mod quiz2;
|
|
||||||
mod quiz3;
|
|
||||||
mod quiz4;
|
|
||||||
mod standard_library_types;
|
|
||||||
mod strings;
|
|
||||||
mod structs;
|
|
||||||
mod tests;
|
|
||||||
mod threads;
|
|
||||||
mod traits;
|
|
||||||
mod variables;
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
mod modules1;
|
|
||||||
mod modules2;
|
|
||||||
mod modules3;
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
// modules1.rs
|
// modules1.rs
|
||||||
// Make me compile! Execute `rustlings hint modules1` for hints :)
|
// Execute `rustlings hint modules1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
// modules2.rs
|
// modules2.rs
|
||||||
// You can bring module paths into scopes and provide new names for them with the
|
// 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.
|
// 'use' and 'as' keywords. Fix these 'use' statements to make the code compile.
|
||||||
// Make me compile! Execute `rustlings hint modules2` for hints :)
|
// Execute `rustlings hint modules2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
mod delicious_snacks {
|
mod delicious_snacks {
|
||||||
|
|
||||||
// TODO: Fix these use statements
|
// TODO: Fix these use statements
|
||||||
use self::fruits::PEAR as ???
|
use self::fruits::PEAR as ???
|
||||||
use self::veggies::CUCUMBER as ???
|
use self::veggies::CUCUMBER as ???
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
// and especially from the Rust standard library into your scope.
|
// and especially from the Rust standard library into your scope.
|
||||||
// Bring SystemTime and UNIX_EPOCH
|
// Bring SystemTime and UNIX_EPOCH
|
||||||
// from the std::time module. Bonus style points if you can do it with one line!
|
// 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 :)
|
// Execute `rustlings hint modules3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
mod move_semantics1;
|
|
||||||
mod move_semantics2;
|
|
||||||
mod move_semantics3;
|
|
||||||
mod move_semantics4;
|
|
||||||
mod move_semantics5;
|
|
||||||
mod move_semantics6;
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
// move_semantics1.rs
|
// move_semantics1.rs
|
||||||
// Make me compile! Execute `rustlings hint move_semantics1` for hints :)
|
// Execute `rustlings hint move_semantics1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// move_semantics2.rs
|
// move_semantics2.rs
|
||||||
// Make me compile without changing line 13 or moving line 10!
|
// Make me compile without changing line 13 or moving line 10!
|
||||||
// Execute `rustlings hint move_semantics2` for hints :)
|
// Execute `rustlings hint move_semantics2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// TOTHINK
|
// TOTHINK
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
// move_semantics3.rs
|
// move_semantics3.rs
|
||||||
// Make me compile without adding new lines-- just changing existing lines!
|
// Make me compile without adding new lines-- just changing existing lines!
|
||||||
// (no lines with multiple semicolons necessary!)
|
// (no lines with multiple semicolons necessary!)
|
||||||
// Execute `rustlings hint move_semantics3` for hints :)
|
// Execute `rustlings hint move_semantics3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
// move_semantics4.rs
|
// move_semantics4.rs
|
||||||
// Refactor this code so that instead of having `vec0` and creating the vector
|
// Refactor this code so that instead of passing `vec0` into the `fill_vec` function,
|
||||||
// in `fn main`, we create it within `fn fill_vec` and transfer the
|
// the Vector gets created in the function itself and passed back to the main
|
||||||
// freshly created vector from fill_vec to its caller.
|
// function.
|
||||||
// Execute `rustlings hint move_semantics4` for hints!
|
// Execute `rustlings hint move_semantics4` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
// move_semantics5.rs
|
// move_semantics5.rs
|
||||||
// Make me compile only by reordering the lines in `main()`, but without
|
// Make me compile only by reordering the lines in `main()`, but without
|
||||||
// adding, changing or removing any of them.
|
// adding, changing or removing any of them.
|
||||||
// Execute `rustlings hint move_semantics5` for hints :)
|
// Execute `rustlings hint move_semantics5` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// TOTHINK
|
// TOTHINK
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// move_semantics6.rs
|
// move_semantics6.rs
|
||||||
// Make me compile! `rustlings hint move_semantics6` for hints
|
// Execute `rustlings hint move_semantics6` or use the `hint` watch subcommand for a hint.
|
||||||
// You can't change anything except adding or removing references
|
// You can't change anything except adding or removing references.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
mod option1;
|
|
||||||
mod option2;
|
|
||||||
mod option3;
|
|
||||||
@ -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 signature
|
|
||||||
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,4 +1,4 @@
|
|||||||
# Option
|
# Options
|
||||||
|
|
||||||
Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not.
|
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:
|
Option types are very common in Rust code, as they have a number of uses:
|
||||||
39
exercises/options/options1.rs
Normal file
39
exercises/options/options1.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// options1.rs
|
||||||
|
// Execute `rustlings hint options1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
// you can modify anything EXCEPT for this function's signature
|
||||||
|
fn print_number(maybe_number: Option<u16>) {
|
||||||
|
println!("printing: {}", maybe_number.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function returns how much icecream there is left in the fridge.
|
||||||
|
// If it's before 10PM, there's 5 pieces left. At 10PM, someone eats them
|
||||||
|
// all, so there'll be no more left :(
|
||||||
|
// TODO: Return an Option!
|
||||||
|
fn maybe_icecream(time_of_day: u16) -> Option<u16> {
|
||||||
|
// We use the 24-hour system here, so 10PM is a value of 22
|
||||||
|
// The Option output should gracefully handle cases where time_of_day > 24.
|
||||||
|
???
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_icecream() {
|
||||||
|
assert_eq!(maybe_icecream(10), Some(5));
|
||||||
|
assert_eq!(maybe_icecream(23), Some(0));
|
||||||
|
assert_eq!(maybe_icecream(22), Some(0));
|
||||||
|
assert_eq!(maybe_icecream(25), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn raw_value() {
|
||||||
|
// TODO: Fix this test. How do you get at the value contained in the Option?
|
||||||
|
let icecreams = maybe_icecream(12);
|
||||||
|
assert_eq!(icecreams, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
// option2.rs
|
// options2.rs
|
||||||
// Make me compile! Execute `rustlings hint option2` for hints
|
// Execute `rustlings hint options2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
// option3.rs
|
// options3.rs
|
||||||
// Make me compile! Execute `rustlings hint option3` for hints
|
// Execute `rustlings hint options3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
mod primitive_types1;
|
|
||||||
mod primitive_types2;
|
|
||||||
mod primitive_types3;
|
|
||||||
mod primitive_types4;
|
|
||||||
mod primitive_types5;
|
|
||||||
mod primitive_types6;
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
// Characters (`char`)
|
// Characters (`char`)
|
||||||
|
|
||||||
|
// Note the _single_ quotes, these are different from the double quotes
|
||||||
|
// you've been seeing around.
|
||||||
let my_first_initial = 'C';
|
let my_first_initial = 'C';
|
||||||
if my_first_initial.is_alphabetic() {
|
if my_first_initial.is_alphabetic() {
|
||||||
println!("Alphabetical!");
|
println!("Alphabetical!");
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// primitive_types3.rs
|
// primitive_types3.rs
|
||||||
// Create an array with at least 100 elements in it where the ??? is.
|
// Create an array with at least 100 elements in it where the ??? is.
|
||||||
// Execute `rustlings hint primitive_types3` for hints!
|
// Execute `rustlings hint primitive_types3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// primitive_types4.rs
|
// primitive_types4.rs
|
||||||
// Get a slice out of Array a where the ??? is so that the test passes.
|
// Get a slice out of Array a where the ??? is so that the test passes.
|
||||||
// Execute `rustlings hint primitive_types4` for hints!!
|
// Execute `rustlings hint primitive_types4` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// primitive_types5.rs
|
// primitive_types5.rs
|
||||||
// Destructure the `cat` tuple so that the println will work.
|
// Destructure the `cat` tuple so that the println will work.
|
||||||
// Execute `rustlings hint primitive_types5` for hints!
|
// Execute `rustlings hint primitive_types5` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
// primitive_types6.rs
|
// primitive_types6.rs
|
||||||
// Use a tuple index to access the second element of `numbers`.
|
// 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.
|
// You can put the expression for the second element where ??? is so that the test passes.
|
||||||
// Execute `rustlings hint primitive_types6` for hints!
|
// Execute `rustlings hint primitive_types6` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -17,13 +17,14 @@ fn calculate_apple_price(quantity: i32) -> i32 {
|
|||||||
return quantity * 2;
|
return quantity * 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// fn calculate_price_of_apples {
|
||||||
|
|
||||||
// Don't modify this function!
|
// Don't modify this function!
|
||||||
#[test]
|
#[test]
|
||||||
fn verify_test() {
|
fn verify_test() {
|
||||||
let price1 = calculate_apple_price(35);
|
let price1 = calculate_price_of_apples(35);
|
||||||
let price2 = calculate_apple_price(40);
|
let price2 = calculate_price_of_apples(40);
|
||||||
let price3 = calculate_apple_price(65);
|
let price3 = calculate_price_of_apples(65);
|
||||||
|
|
||||||
assert_eq!(70, price1);
|
assert_eq!(70, price1);
|
||||||
assert_eq!(80, price2);
|
assert_eq!(80, price2);
|
||||||
|
|||||||
@ -1,30 +1,62 @@
|
|||||||
// quiz2.rs
|
// quiz2.rs
|
||||||
// This is a quiz for the following sections:
|
// This is a quiz for the following sections:
|
||||||
// - Strings
|
// - Strings
|
||||||
|
// - Vecs
|
||||||
|
// - Move semantics
|
||||||
|
// - Modules
|
||||||
|
// - Enums
|
||||||
|
|
||||||
// Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your
|
// Let's build a little machine in form of a function.
|
||||||
// task is to call one of these two functions on each value depending on what
|
// As input, we're going to give a list of strings and commands. These commands
|
||||||
// you think each value is. That is, add either `string_slice` or `string`
|
// determine what action is going to be applied to the string. It can either be:
|
||||||
// before the parentheses on each line. If you're right, it will compile!
|
// - Uppercase the string
|
||||||
|
// - Trim the string
|
||||||
|
// - Append "bar" to the string a specified amount of times
|
||||||
|
// The exact form of this will be:
|
||||||
|
// - The input is going to be a Vector of a 2-length tuple,
|
||||||
|
// the first element is the string, the second one is the command.
|
||||||
|
// - The output element is going to be a Vector of strings.
|
||||||
|
// Execute `rustlings hint quiz2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
fn string_slice(arg: &str) {
|
pub enum Command {
|
||||||
println!("{}", arg);
|
Uppercase,
|
||||||
}
|
Trim,
|
||||||
fn string(arg: String) {
|
Append(usize),
|
||||||
println!("{}", arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
mod my_module {
|
||||||
???("blue");
|
use super::Command;
|
||||||
???("red".to_string());
|
|
||||||
???(String::from("hi"));
|
// TODO: Complete the function signature!
|
||||||
???("rust is fun!".to_owned());
|
pub fn transformer(input: ???) -> ??? {
|
||||||
???("nice weather".into());
|
// TODO: Complete the output declaration!
|
||||||
???(format!("Interpolation {}", "Station"));
|
let mut output: ??? = vec![];
|
||||||
???(&String::from("abc")[0..1]);
|
for (string, command) in input.iter() {
|
||||||
???(" hello there ".trim());
|
// TODO: Complete the function body. You can do it!
|
||||||
???("Happy Monday!".to_string().replace("Mon", "Tues"));
|
}
|
||||||
???("mY sHiFt KeY iS sTiCkY".to_lowercase());
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
// TODO: What to we have to import to have `transformer` in scope?
|
||||||
|
use ???;
|
||||||
|
use super::Command;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
let output = transformer(vec![
|
||||||
|
("hello".into(), Command::Uppercase),
|
||||||
|
(" all roads lead to rome! ".into(), Command::Trim),
|
||||||
|
("foo".into(), Command::Append(1)),
|
||||||
|
("bar".into(), Command::Append(5)),
|
||||||
|
]);
|
||||||
|
assert_eq!(output[0], "HELLO");
|
||||||
|
assert_eq!(output[1], "all roads lead to rome!");
|
||||||
|
assert_eq!(output[2], "foobar");
|
||||||
|
assert_eq!(output[3], "barbarbarbarbarbar");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,32 @@
|
|||||||
// quiz3.rs
|
// quiz3.rs
|
||||||
// This is a quiz for the following sections:
|
// This quiz tests:
|
||||||
// - Tests
|
// - Generics
|
||||||
|
// - Traits
|
||||||
|
// 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!
|
||||||
|
|
||||||
// This quiz isn't testing our function -- make it do that in such a way that
|
// Make the necessary code changes in the struct ReportCard and the impl block
|
||||||
// the test passes. Then write a second test that tests that we get the result
|
// to support alphabetical report cards. Change the Grade in the second test to "A+"
|
||||||
// we expect to get when we call `times_two` with a negative number.
|
// to show that your changes allow alphabetical grades.
|
||||||
// No hints, you can do this :)
|
|
||||||
|
// Execute `rustlings hint quiz3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
pub fn times_two(num: i32) -> i32 {
|
pub struct ReportCard {
|
||||||
num * 2
|
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)]
|
#[cfg(test)]
|
||||||
@ -18,13 +34,29 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn returns_twice_of_positive_numbers() {
|
fn generate_numeric_report_card() {
|
||||||
assert_eq!(times_two(4), ???);
|
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]
|
#[test]
|
||||||
fn returns_twice_of_negative_numbers() {
|
fn generate_alphabetic_report_card() {
|
||||||
// TODO replace unimplemented!() with an assert for `times_two(-4)`
|
// TODO: Make sure to change the grade here after you finish the exercise.
|
||||||
unimplemented!()
|
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,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!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -16,7 +16,7 @@
|
|||||||
// Make this code compile by filling in a value for `shared_numbers` where the
|
// 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`
|
// 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!
|
// where the second TODO comment is. Try not to create any copies of the `numbers` Vec!
|
||||||
// Execute `rustlings hint arc1` for hints :)
|
// Execute `rustlings hint arc1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -10,11 +10,11 @@
|
|||||||
// elements: the value of the current item and the next item. The last item is a value called `Nil`.
|
// 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 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!()`
|
// Step 2: create both empty and non-empty cons lists by replacing `todo!()`
|
||||||
//
|
//
|
||||||
// Note: the tests should not be changed
|
// Note: the tests should not be changed
|
||||||
//
|
//
|
||||||
// Execute `rustlings hint box1` for hints :)
|
// Execute `rustlings hint box1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
@ -33,11 +33,11 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_empty_list() -> List {
|
pub fn create_empty_list() -> List {
|
||||||
unimplemented!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_non_empty_list() -> List {
|
pub fn create_non_empty_list() -> List {
|
||||||
unimplemented!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
// This module helps you get familiar with the structure of using an iterator and
|
// This module helps you get familiar with the structure of using an iterator and
|
||||||
// how to go through elements within an iterable collection.
|
// how to go through elements within an iterable collection.
|
||||||
//
|
//
|
||||||
// Execute `rustlings hint iterators1` for hints :D
|
// Execute `rustlings hint iterators1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
// iterators2.rs
|
// iterators2.rs
|
||||||
// In this exercise, you'll learn some of the unique advantages that iterators
|
// In this exercise, you'll learn some of the unique advantages that iterators
|
||||||
// can offer. Follow the steps to complete the exercise.
|
// can offer. Follow the steps to complete the exercise.
|
||||||
// As always, there are hints if you execute `rustlings hint iterators2`!
|
// Execute `rustlings hint iterators2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user